perf tools changes and fixes for v6.5: 1st batch

Internal cleanup:
 
  - Refactor PMU data management to handle hybrid systems in a generic way.
    Do more work in the lexer so that legacy event types parse more easily.
    A side-effect of this is that if a PMU is specified, scanning sysfs is
    avoided improving start-up time.
 
  - Fix hybrid metrics, for example, the TopdownL1 works for both performance
    and efficiency cores on Intel machines.  To support this, sort and regroup
    events after parsing.
 
  - Add reference count checking for the 'thread' data structure.
 
  - Lots of fixes for memory leaks in various places thanks to the ASAN and
    Ian's refcount checker.
 
  - Reduce the binary size by replacing static variables with local or
    dynamically allocated memory.
 
  - Introduce shared_mutex for annotate data to reduce memory footprint.
 
  - Make filesystem access library functions more thread safe.
 
 Test:
 
  - Organize cpu_map tests into a single suite.
 
  - Add metric value validation test to check if the values are within correct
    value ranges.
 
  - Add perf stat stdio output test to check if event and metric names match.
 
  - Add perf data converter JSON output test.
 
  - Fix a lot of issues reported by shellcheck(1).  This is a preparation to
    enable shellcheck by default.
 
  - Make the large x86 new instructions test optional at build time using
    EXTRA_TESTS=1.
 
  - Add a test for libpfm4 events.
 
 perf script:
 
  - Add 'dsoff' outpuf field to display offset from the DSO.
 
     $ perf script -F comm,pid,event,ip,dsoff
        ls 2695501 cycles:      152cc73ef4b5 (/usr/lib/x86_64-linux-gnu/ld-2.31.so+0x1c4b5)
        ls 2695501 cycles:  ffffffff99045b3e ([kernel.kallsyms])
        ls 2695501 cycles:  ffffffff9968e107 ([kernel.kallsyms])
        ls 2695501 cycles:  ffffffffc1f54afb ([kernel.kallsyms])
        ls 2695501 cycles:  ffffffff9968382f ([kernel.kallsyms])
        ls 2695501 cycles:  ffffffff99e00094 ([kernel.kallsyms])
        ls 2695501 cycles:      152cc718a8d0 (/usr/lib/x86_64-linux-gnu/libselinux.so.1+0x68d0)
        ls 2695501 cycles:  ffffffff992a6db0 ([kernel.kallsyms])
 
  - Adjust width for large PID/TID values.
 
 perf report:
 
  - Robustify reading addr2line output for srcline by checking sentinel output
    before the actual data and by using timeout of 1 second.
 
  - Allow config terms (like 'name=ABC') with breakpoint events.
 
     $ perf record -e mem:0x55feb98dd169:x/name=breakpoint/ -p 19646 -- sleep 1
 
 perf annotate:
 
  - Handle x86 instruction suffix like 'l' in 'movl' generally.
 
  - Parse instruction operands properly even with a whitespace.  This is needed
    for llvm-objdump output.
 
  - Support RISC-V binutils lookup using the triplet prefixes.
 
  - Add '<' and '>' key to navigate to prev/next symbols in TUI.
 
  - Fix instruction association and parsing for LoongArch.
 
 perf stat:
 
  - Add --per-cache aggregation option, optionally specify a cache level
    like `--per-cache=L2`.
 
     $ sudo perf stat --per-cache -a -e ls_dmnd_fills_from_sys.ext_cache_remote --\
       taskset -c 0-15,64-79,128-143,192-207\
       perf bench sched messaging -p -t -l 100000 -g 8
 
       # Running 'sched/messaging' benchmark:
       # 20 sender and receiver threads per group
       # 8 groups == 320 threads run
 
       Total time: 7.648 [sec]
 
       Performance counter stats for 'system wide':
 
       S0-D0-L3-ID0             16         17,145,912      ls_dmnd_fills_from_sys.ext_cache_remote
       S0-D0-L3-ID8             16         14,977,628      ls_dmnd_fills_from_sys.ext_cache_remote
       S0-D0-L3-ID16            16            262,539      ls_dmnd_fills_from_sys.ext_cache_remote
       S0-D0-L3-ID24            16              3,140      ls_dmnd_fills_from_sys.ext_cache_remote
       S0-D0-L3-ID32            16             27,403      ls_dmnd_fills_from_sys.ext_cache_remote
       S0-D0-L3-ID40            16             17,026      ls_dmnd_fills_from_sys.ext_cache_remote
       S0-D0-L3-ID48            16              7,292      ls_dmnd_fills_from_sys.ext_cache_remote
       S0-D0-L3-ID56            16              2,464      ls_dmnd_fills_from_sys.ext_cache_remote
       S1-D1-L3-ID64            16         22,489,306      ls_dmnd_fills_from_sys.ext_cache_remote
       S1-D1-L3-ID72            16         21,455,257      ls_dmnd_fills_from_sys.ext_cache_remote
       S1-D1-L3-ID80            16             11,619      ls_dmnd_fills_from_sys.ext_cache_remote
       S1-D1-L3-ID88            16             30,978      ls_dmnd_fills_from_sys.ext_cache_remote
       S1-D1-L3-ID96            16             37,628      ls_dmnd_fills_from_sys.ext_cache_remote
       S1-D1-L3-ID104           16             13,594      ls_dmnd_fills_from_sys.ext_cache_remote
       S1-D1-L3-ID112           16             10,164      ls_dmnd_fills_from_sys.ext_cache_remote
       S1-D1-L3-ID120           16             11,259      ls_dmnd_fills_from_sys.ext_cache_remote
 
             7.779171484 seconds time elapsed
 
   - Change default (no event/metric) formatting for default metrics so that
     events are hidden and the metric and group appear.
 
      Performance counter stats for 'ls /':
 
                   1.85 msec task-clock                       #    0.594 CPUs utilized
                      0      context-switches                 #    0.000 /sec
                      0      cpu-migrations                   #    0.000 /sec
                     97      page-faults                      #   52.517 K/sec
              2,187,173      cycles                           #    1.184 GHz
              2,474,459      instructions                     #    1.13  insn per cycle
                531,584      branches                         #  287.805 M/sec
                 13,626      branch-misses                    #    2.56% of all branches
                             TopdownL1                 #     23.5 %  tma_backend_bound
                                                       #     11.5 %  tma_bad_speculation
                                                       #     39.1 %  tma_frontend_bound
                                                       #     25.9 %  tma_retiring
 
  - Allow --cputype option to have any PMU name (not just hybrid).
 
  - Fix output value not to added when it runs multiple times with -r option.
 
 perf list:
 
  - Show metricgroup description from JSON file called metricgroups.json.
 
  - Allow 'pfm' argument to list only libpfm4 events and check each event is
    supported before showing it.
 
 JSON vendor events:
 
  - Avoid event grouping using "NO_GROUP_EVENTS" constraints.  The topdown
    events are correctly grouped even if no group exists.
 
  - Add "Default" metric group to print it in the default output.  And use
    "DefaultMetricgroupName" to indicate the real metric group name.
 
  - Add AmpereOne core PMU events.
 
 Misc:
 
  - Define man page date correctly.
 
  - Track exception level properly on ARM CoreSight ETM.
 
  - Allow anonymous struct, union or enum when retrieving type names from DWARF.
 
  - Fix incorrect filename when calling `perf inject --jit`.
 
  - Handle PLT size correctly on LoongArch.
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQSo2x5BnqMqsoHtzsmMstVUGiXMgwUCZJxT3gAKCRCMstVUGiXM
 g3//AQDyH3tbAVxU6JkvEOjjDvK7MWeXef7GQh8MP8D9Wkxk1AD9HgyxZWXn+mer
 wxzBMntnxlr9+mkBerrVwUzYMd/IJQk=
 =hPh8
 -----END PGP SIGNATURE-----

Merge tag 'perf-tools-for-v6.5-1-2023-06-28' of git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next

Pull perf tools updates from Namhyung Kim:
 "Internal cleanup:

   - Refactor PMU data management to handle hybrid systems in a generic
     way.

     Do more work in the lexer so that legacy event types parse more
     easily. A side-effect of this is that if a PMU is specified,
     scanning sysfs is avoided improving start-up time.

   - Fix hybrid metrics, for example, the TopdownL1 works for both
     performance and efficiency cores on Intel machines. To support
     this, sort and regroup events after parsing.

   - Add reference count checking for the 'thread' data structure.

   - Lots of fixes for memory leaks in various places thanks to the ASAN
     and Ian's refcount checker.

   - Reduce the binary size by replacing static variables with local or
     dynamically allocated memory.

   - Introduce shared_mutex for annotate data to reduce memory
     footprint.

   - Make filesystem access library functions more thread safe.

  Test:

   - Organize cpu_map tests into a single suite.

   - Add metric value validation test to check if the values are within
     correct value ranges.

   - Add perf stat stdio output test to check if event and metric names
     match.

   - Add perf data converter JSON output test.

   - Fix a lot of issues reported by shellcheck(1). This is a
     preparation to enable shellcheck by default.

   - Make the large x86 new instructions test optional at build time
     using EXTRA_TESTS=1.

   - Add a test for libpfm4 events.

  perf script:

   - Add 'dsoff' outpuf field to display offset from the DSO.

      $ perf script -F comm,pid,event,ip,dsoff
         ls 2695501 cycles:      152cc73ef4b5 (/usr/lib/x86_64-linux-gnu/ld-2.31.so+0x1c4b5)
         ls 2695501 cycles:  ffffffff99045b3e ([kernel.kallsyms])
         ls 2695501 cycles:  ffffffff9968e107 ([kernel.kallsyms])
         ls 2695501 cycles:  ffffffffc1f54afb ([kernel.kallsyms])
         ls 2695501 cycles:  ffffffff9968382f ([kernel.kallsyms])
         ls 2695501 cycles:  ffffffff99e00094 ([kernel.kallsyms])
         ls 2695501 cycles:      152cc718a8d0 (/usr/lib/x86_64-linux-gnu/libselinux.so.1+0x68d0)
         ls 2695501 cycles:  ffffffff992a6db0 ([kernel.kallsyms])

   - Adjust width for large PID/TID values.

  perf report:

   - Robustify reading addr2line output for srcline by checking sentinel
     output before the actual data and by using timeout of 1 second.

   - Allow config terms (like 'name=ABC') with breakpoint events.

      $ perf record -e mem:0x55feb98dd169:x/name=breakpoint/ -p 19646 -- sleep 1

  perf annotate:

   - Handle x86 instruction suffix like 'l' in 'movl' generally.

   - Parse instruction operands properly even with a whitespace. This is
     needed for llvm-objdump output.

   - Support RISC-V binutils lookup using the triplet prefixes.

   - Add '<' and '>' key to navigate to prev/next symbols in TUI.

   - Fix instruction association and parsing for LoongArch.

  perf stat:

   - Add --per-cache aggregation option, optionally specify a cache
     level like `--per-cache=L2`.

      $ sudo perf stat --per-cache -a -e ls_dmnd_fills_from_sys.ext_cache_remote --\
        taskset -c 0-15,64-79,128-143,192-207\
        perf bench sched messaging -p -t -l 100000 -g 8

        # Running 'sched/messaging' benchmark:
        # 20 sender and receiver threads per group
        # 8 groups == 320 threads run

        Total time: 7.648 [sec]

        Performance counter stats for 'system wide':

        S0-D0-L3-ID0             16         17,145,912      ls_dmnd_fills_from_sys.ext_cache_remote
        S0-D0-L3-ID8             16         14,977,628      ls_dmnd_fills_from_sys.ext_cache_remote
        S0-D0-L3-ID16            16            262,539      ls_dmnd_fills_from_sys.ext_cache_remote
        S0-D0-L3-ID24            16              3,140      ls_dmnd_fills_from_sys.ext_cache_remote
        S0-D0-L3-ID32            16             27,403      ls_dmnd_fills_from_sys.ext_cache_remote
        S0-D0-L3-ID40            16             17,026      ls_dmnd_fills_from_sys.ext_cache_remote
        S0-D0-L3-ID48            16              7,292      ls_dmnd_fills_from_sys.ext_cache_remote
        S0-D0-L3-ID56            16              2,464      ls_dmnd_fills_from_sys.ext_cache_remote
        S1-D1-L3-ID64            16         22,489,306      ls_dmnd_fills_from_sys.ext_cache_remote
        S1-D1-L3-ID72            16         21,455,257      ls_dmnd_fills_from_sys.ext_cache_remote
        S1-D1-L3-ID80            16             11,619      ls_dmnd_fills_from_sys.ext_cache_remote
        S1-D1-L3-ID88            16             30,978      ls_dmnd_fills_from_sys.ext_cache_remote
        S1-D1-L3-ID96            16             37,628      ls_dmnd_fills_from_sys.ext_cache_remote
        S1-D1-L3-ID104           16             13,594      ls_dmnd_fills_from_sys.ext_cache_remote
        S1-D1-L3-ID112           16             10,164      ls_dmnd_fills_from_sys.ext_cache_remote
        S1-D1-L3-ID120           16             11,259      ls_dmnd_fills_from_sys.ext_cache_remote

              7.779171484 seconds time elapsed

   - Change default (no event/metric) formatting for default metrics so
     that events are hidden and the metric and group appear.

       Performance counter stats for 'ls /':

                    1.85 msec task-clock                       #    0.594 CPUs utilized
                       0      context-switches                 #    0.000 /sec
                       0      cpu-migrations                   #    0.000 /sec
                      97      page-faults                      #   52.517 K/sec
               2,187,173      cycles                           #    1.184 GHz
               2,474,459      instructions                     #    1.13  insn per cycle
                 531,584      branches                         #  287.805 M/sec
                  13,626      branch-misses                    #    2.56% of all branches
                              TopdownL1                 #     23.5 %  tma_backend_bound
                                                        #     11.5 %  tma_bad_speculation
                                                        #     39.1 %  tma_frontend_bound
                                                        #     25.9 %  tma_retiring

   - Allow --cputype option to have any PMU name (not just hybrid).

   - Fix output value not to added when it runs multiple times with -r
     option.

  perf list:

   - Show metricgroup description from JSON file called
     metricgroups.json.

   - Allow 'pfm' argument to list only libpfm4 events and check each
     event is supported before showing it.

  JSON vendor events:

   - Avoid event grouping using "NO_GROUP_EVENTS" constraints. The
     topdown events are correctly grouped even if no group exists.

   - Add "Default" metric group to print it in the default output. And
     use "DefaultMetricgroupName" to indicate the real metric group
     name.

   - Add AmpereOne core PMU events.

  Misc:

   - Define man page date correctly.

   - Track exception level properly on ARM CoreSight ETM.

   - Allow anonymous struct, union or enum when retrieving type names
     from DWARF.

   - Fix incorrect filename when calling `perf inject --jit`.

   - Handle PLT size correctly on LoongArch"

* tag 'perf-tools-for-v6.5-1-2023-06-28' of git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next: (269 commits)
  perf test: Skip metrics w/o event name in stat STD output linter
  perf test: Reorder event name checks in stat STD output linter
  perf pmu: Remove a hard coded cpu PMU assumption
  perf pmus: Add notion of default PMU for JSON events
  perf unwind: Fix map reference counts
  perf test: Set PERF_EXEC_PATH for script execution
  perf script: Initialize buffer for regs_map()
  perf tests: Fix test_arm_callgraph_fp variable expansion
  perf symbol: Add LoongArch case in get_plt_sizes()
  perf test: Remove x permission from lib/stat_output.sh
  perf test: Rerun failed metrics with longer workload
  perf test: Add skip list for metrics known would fail
  perf test: Add metric value validation test
  perf jit: Fix incorrect file name in DWARF line table
  perf annotate: Fix instruction association and parsing for LoongArch
  perf annotation: Switch lock from a mutex to a sharded_mutex
  perf sharded_mutex: Introduce sharded_mutex
  tools: Fix incorrect calculation of object size by sizeof
  perf subcmd: Fix missing check for return value of malloc() in add_cmdname()
  perf parse-events: Remove unneeded semicolon
  ...
This commit is contained in:
Linus Torvalds 2023-06-30 11:35:41 -07:00
commit b30d7a77c5
324 changed files with 21514 additions and 12997 deletions

View File

@ -14,7 +14,7 @@ struct cgroupfs_cache_entry {
};
/* just cache last used one */
static struct cgroupfs_cache_entry cached;
static struct cgroupfs_cache_entry *cached;
int cgroupfs_find_mountpoint(char *buf, size_t maxlen, const char *subsys)
{
@ -24,9 +24,9 @@ int cgroupfs_find_mountpoint(char *buf, size_t maxlen, const char *subsys)
char *p, *path;
char mountpoint[PATH_MAX];
if (!strcmp(cached.subsys, subsys)) {
if (strlen(cached.mountpoint) < maxlen) {
strcpy(buf, cached.mountpoint);
if (cached && !strcmp(cached->subsys, subsys)) {
if (strlen(cached->mountpoint) < maxlen) {
strcpy(buf, cached->mountpoint);
return 0;
}
return -1;
@ -91,8 +91,13 @@ int cgroupfs_find_mountpoint(char *buf, size_t maxlen, const char *subsys)
free(line);
fclose(fp);
strncpy(cached.subsys, subsys, sizeof(cached.subsys) - 1);
strcpy(cached.mountpoint, mountpoint);
if (!cached)
cached = calloc(1, sizeof(*cached));
if (cached) {
strncpy(cached->subsys, subsys, sizeof(cached->subsys) - 1);
strcpy(cached->mountpoint, mountpoint);
}
if (mountpoint[0] && strlen(mountpoint) < maxlen) {
strcpy(buf, mountpoint);

View File

@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
@ -10,6 +11,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/mount.h>
@ -43,7 +45,7 @@
#define BPF_FS_MAGIC 0xcafe4a11
#endif
static const char * const sysfs__fs_known_mountpoints[] = {
static const char * const sysfs__known_mountpoints[] = {
"/sys",
0,
};
@ -86,87 +88,89 @@ static const char * const bpf_fs__known_mountpoints[] = {
};
struct fs {
const char *name;
const char * const *mounts;
char path[PATH_MAX];
bool found;
bool checked;
long magic;
};
enum {
FS__SYSFS = 0,
FS__PROCFS = 1,
FS__DEBUGFS = 2,
FS__TRACEFS = 3,
FS__HUGETLBFS = 4,
FS__BPF_FS = 5,
const char * const name;
const char * const * const mounts;
char *path;
pthread_mutex_t mount_mutex;
const long magic;
};
#ifndef TRACEFS_MAGIC
#define TRACEFS_MAGIC 0x74726163
#endif
static struct fs fs__entries[] = {
[FS__SYSFS] = {
.name = "sysfs",
.mounts = sysfs__fs_known_mountpoints,
.magic = SYSFS_MAGIC,
.checked = false,
},
[FS__PROCFS] = {
.name = "proc",
.mounts = procfs__known_mountpoints,
.magic = PROC_SUPER_MAGIC,
.checked = false,
},
[FS__DEBUGFS] = {
.name = "debugfs",
.mounts = debugfs__known_mountpoints,
.magic = DEBUGFS_MAGIC,
.checked = false,
},
[FS__TRACEFS] = {
.name = "tracefs",
.mounts = tracefs__known_mountpoints,
.magic = TRACEFS_MAGIC,
.checked = false,
},
[FS__HUGETLBFS] = {
.name = "hugetlbfs",
.mounts = hugetlbfs__known_mountpoints,
.magic = HUGETLBFS_MAGIC,
.checked = false,
},
[FS__BPF_FS] = {
.name = "bpf",
.mounts = bpf_fs__known_mountpoints,
.magic = BPF_FS_MAGIC,
.checked = false,
},
};
static void fs__init_once(struct fs *fs);
static const char *fs__mountpoint(const struct fs *fs);
static const char *fs__mount(struct fs *fs);
#define FS(lower_name, fs_name, upper_name) \
static struct fs fs__##lower_name = { \
.name = #fs_name, \
.mounts = lower_name##__known_mountpoints, \
.magic = upper_name##_MAGIC, \
.mount_mutex = PTHREAD_MUTEX_INITIALIZER, \
}; \
\
static void lower_name##_init_once(void) \
{ \
struct fs *fs = &fs__##lower_name; \
\
fs__init_once(fs); \
} \
\
const char *lower_name##__mountpoint(void) \
{ \
static pthread_once_t init_once = PTHREAD_ONCE_INIT; \
struct fs *fs = &fs__##lower_name; \
\
pthread_once(&init_once, lower_name##_init_once); \
return fs__mountpoint(fs); \
} \
\
const char *lower_name##__mount(void) \
{ \
const char *mountpoint = lower_name##__mountpoint(); \
struct fs *fs = &fs__##lower_name; \
\
if (mountpoint) \
return mountpoint; \
\
return fs__mount(fs); \
} \
\
bool lower_name##__configured(void) \
{ \
return lower_name##__mountpoint() != NULL; \
}
FS(sysfs, sysfs, SYSFS);
FS(procfs, procfs, PROC_SUPER);
FS(debugfs, debugfs, DEBUGFS);
FS(tracefs, tracefs, TRACEFS);
FS(hugetlbfs, hugetlbfs, HUGETLBFS);
FS(bpf_fs, bpf, BPF_FS);
static bool fs__read_mounts(struct fs *fs)
{
bool found = false;
char type[100];
FILE *fp;
char path[PATH_MAX + 1];
fp = fopen("/proc/mounts", "r");
if (fp == NULL)
return NULL;
return false;
while (!found &&
fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
fs->path, type) == 2) {
while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
path, type) == 2) {
if (strcmp(type, fs->name) == 0)
found = true;
if (strcmp(type, fs->name) == 0) {
fs->path = strdup(path);
fclose(fp);
return fs->path != NULL;
}
}
fclose(fp);
fs->checked = true;
return fs->found = found;
return false;
}
static int fs__valid_mount(const char *fs, long magic)
@ -188,8 +192,9 @@ static bool fs__check_mounts(struct fs *fs)
ptr = fs->mounts;
while (*ptr) {
if (fs__valid_mount(*ptr, fs->magic) == 0) {
fs->found = true;
strcpy(fs->path, *ptr);
fs->path = strdup(*ptr);
if (!fs->path)
return false;
return true;
}
ptr++;
@ -227,43 +232,26 @@ static bool fs__env_override(struct fs *fs)
if (!override_path)
return false;
fs->found = true;
fs->checked = true;
strncpy(fs->path, override_path, sizeof(fs->path) - 1);
fs->path[sizeof(fs->path) - 1] = '\0';
fs->path = strdup(override_path);
if (!fs->path)
return false;
return true;
}
static const char *fs__get_mountpoint(struct fs *fs)
static void fs__init_once(struct fs *fs)
{
if (fs__env_override(fs))
return fs->path;
if (fs__check_mounts(fs))
return fs->path;
if (fs__read_mounts(fs))
return fs->path;
return NULL;
if (!fs__env_override(fs) &&
!fs__check_mounts(fs) &&
!fs__read_mounts(fs)) {
assert(!fs->path);
} else {
assert(fs->path);
}
}
static const char *fs__mountpoint(int idx)
static const char *fs__mountpoint(const struct fs *fs)
{
struct fs *fs = &fs__entries[idx];
if (fs->found)
return (const char *)fs->path;
/* the mount point was already checked for the mount point
* but and did not exist, so return NULL to avoid scanning again.
* This makes the found and not found paths cost equivalent
* in case of multiple calls.
*/
if (fs->checked)
return NULL;
return fs__get_mountpoint(fs);
return fs->path;
}
static const char *mount_overload(struct fs *fs)
@ -278,45 +266,29 @@ static const char *mount_overload(struct fs *fs)
return getenv(upper_name) ?: *fs->mounts;
}
static const char *fs__mount(int idx)
static const char *fs__mount(struct fs *fs)
{
struct fs *fs = &fs__entries[idx];
const char *mountpoint;
if (fs__mountpoint(idx))
return (const char *)fs->path;
pthread_mutex_lock(&fs->mount_mutex);
/* Check if path found inside the mutex to avoid races with other callers of mount. */
mountpoint = fs__mountpoint(fs);
if (mountpoint)
goto out;
mountpoint = mount_overload(fs);
if (mount(NULL, mountpoint, fs->name, 0, NULL) < 0)
return NULL;
return fs__check_mounts(fs) ? fs->path : NULL;
if (mount(NULL, mountpoint, fs->name, 0, NULL) == 0 &&
fs__valid_mount(mountpoint, fs->magic) == 0) {
fs->path = strdup(mountpoint);
mountpoint = fs->path;
}
out:
pthread_mutex_unlock(&fs->mount_mutex);
return mountpoint;
}
#define FS(name, idx) \
const char *name##__mountpoint(void) \
{ \
return fs__mountpoint(idx); \
} \
\
const char *name##__mount(void) \
{ \
return fs__mount(idx); \
} \
\
bool name##__configured(void) \
{ \
return name##__mountpoint() != NULL; \
}
FS(sysfs, FS__SYSFS);
FS(procfs, FS__PROCFS);
FS(debugfs, FS__DEBUGFS);
FS(tracefs, FS__TRACEFS);
FS(hugetlbfs, FS__HUGETLBFS);
FS(bpf_fs, FS__BPF_FS);
int filename__read_int(const char *filename, int *value)
{
char line[64];

View File

@ -13,17 +13,12 @@
#include "tracing_path.h"
static char tracing_mnt[PATH_MAX] = "/sys/kernel/debug";
static char tracing_path[PATH_MAX] = "/sys/kernel/tracing";
static char tracing_events_path[PATH_MAX] = "/sys/kernel/tracing/events";
static void __tracing_path_set(const char *tracing, const char *mountpoint)
{
snprintf(tracing_mnt, sizeof(tracing_mnt), "%s", mountpoint);
snprintf(tracing_path, sizeof(tracing_path), "%s/%s",
mountpoint, tracing);
snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s%s",
mountpoint, tracing, "events");
}
static const char *tracing_path_tracefs_mount(void)
@ -149,15 +144,15 @@ int tracing_path__strerror_open_tp(int err, char *buf, size_t size,
/* sdt markers */
if (!strncmp(filename, "sdt_", 4)) {
snprintf(buf, size,
"Error:\tFile %s/%s not found.\n"
"Error:\tFile %s/events/%s not found.\n"
"Hint:\tSDT event cannot be directly recorded on.\n"
"\tPlease first use 'perf probe %s:%s' before recording it.\n",
tracing_events_path, filename, sys, name);
tracing_path, filename, sys, name);
} else {
snprintf(buf, size,
"Error:\tFile %s/%s not found.\n"
"Error:\tFile %s/events/%s not found.\n"
"Hint:\tPerhaps this kernel misses some CONFIG_ setting to enable this feature?.\n",
tracing_events_path, filename);
tracing_path, filename);
}
break;
}
@ -169,9 +164,9 @@ int tracing_path__strerror_open_tp(int err, char *buf, size_t size,
break;
case EACCES: {
snprintf(buf, size,
"Error:\tNo permissions to read %s/%s\n"
"Error:\tNo permissions to read %s/events/%s\n"
"Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n",
tracing_events_path, filename, tracing_path_mount());
tracing_path, filename, tracing_path_mount());
}
break;
default:

View File

@ -8,6 +8,7 @@
#define __API_IO__
#include <errno.h>
#include <poll.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@ -23,6 +24,8 @@ struct io {
char *end;
/* Currently accessed data pointer. */
char *data;
/* Read timeout, 0 implies no timeout. */
int timeout_ms;
/* Set true on when the end of file on read error. */
bool eof;
};
@ -35,6 +38,7 @@ static inline void io__init(struct io *io, int fd,
io->buf = buf;
io->end = buf;
io->data = buf;
io->timeout_ms = 0;
io->eof = false;
}
@ -47,7 +51,29 @@ static inline int io__get_char(struct io *io)
return -1;
if (ptr == io->end) {
ssize_t n = read(io->fd, io->buf, io->buf_len);
ssize_t n;
if (io->timeout_ms != 0) {
struct pollfd pfds[] = {
{
.fd = io->fd,
.events = POLLIN,
},
};
n = poll(pfds, 1, io->timeout_ms);
if (n == 0)
errno = ETIMEDOUT;
if (n > 0 && !(pfds[0].revents & POLLIN)) {
errno = EIO;
n = -1;
}
if (n <= 0) {
io->eof = true;
return -1;
}
}
n = read(io->fd, io->buf, io->buf_len);
if (n <= 0) {
io->eof = true;

View File

@ -99,6 +99,11 @@ static int cmp_cpu(const void *a, const void *b)
return cpu_a->cpu - cpu_b->cpu;
}
static struct perf_cpu __perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx)
{
return RC_CHK_ACCESS(cpus)->map[idx];
}
static struct perf_cpu_map *cpu_map__trim_new(int nr_cpus, const struct perf_cpu *tmp_cpus)
{
size_t payload_size = nr_cpus * sizeof(struct perf_cpu);
@ -111,8 +116,12 @@ static struct perf_cpu_map *cpu_map__trim_new(int nr_cpus, const struct perf_cpu
/* Remove dups */
j = 0;
for (i = 0; i < nr_cpus; i++) {
if (i == 0 || RC_CHK_ACCESS(cpus)->map[i].cpu != RC_CHK_ACCESS(cpus)->map[i - 1].cpu)
RC_CHK_ACCESS(cpus)->map[j++].cpu = RC_CHK_ACCESS(cpus)->map[i].cpu;
if (i == 0 ||
__perf_cpu_map__cpu(cpus, i).cpu !=
__perf_cpu_map__cpu(cpus, i - 1).cpu) {
RC_CHK_ACCESS(cpus)->map[j++].cpu =
__perf_cpu_map__cpu(cpus, i).cpu;
}
}
perf_cpu_map__set_nr(cpus, j);
assert(j <= nr_cpus);
@ -269,26 +278,31 @@ out:
return cpus;
}
static int __perf_cpu_map__nr(const struct perf_cpu_map *cpus)
{
return RC_CHK_ACCESS(cpus)->nr;
}
struct perf_cpu perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx)
{
struct perf_cpu result = {
.cpu = -1
};
if (cpus && idx < RC_CHK_ACCESS(cpus)->nr)
return RC_CHK_ACCESS(cpus)->map[idx];
if (cpus && idx < __perf_cpu_map__nr(cpus))
return __perf_cpu_map__cpu(cpus, idx);
return result;
}
int perf_cpu_map__nr(const struct perf_cpu_map *cpus)
{
return cpus ? RC_CHK_ACCESS(cpus)->nr : 1;
return cpus ? __perf_cpu_map__nr(cpus) : 1;
}
bool perf_cpu_map__empty(const struct perf_cpu_map *map)
{
return map ? RC_CHK_ACCESS(map)->map[0].cpu == -1 : true;
return map ? __perf_cpu_map__cpu(map, 0).cpu == -1 : true;
}
int perf_cpu_map__idx(const struct perf_cpu_map *cpus, struct perf_cpu cpu)
@ -299,10 +313,10 @@ int perf_cpu_map__idx(const struct perf_cpu_map *cpus, struct perf_cpu cpu)
return -1;
low = 0;
high = RC_CHK_ACCESS(cpus)->nr;
high = __perf_cpu_map__nr(cpus);
while (low < high) {
int idx = (low + high) / 2;
struct perf_cpu cpu_at_idx = RC_CHK_ACCESS(cpus)->map[idx];
struct perf_cpu cpu_at_idx = __perf_cpu_map__cpu(cpus, idx);
if (cpu_at_idx.cpu == cpu.cpu)
return idx;
@ -321,6 +335,32 @@ bool perf_cpu_map__has(const struct perf_cpu_map *cpus, struct perf_cpu cpu)
return perf_cpu_map__idx(cpus, cpu) != -1;
}
bool perf_cpu_map__equal(const struct perf_cpu_map *lhs, const struct perf_cpu_map *rhs)
{
int nr;
if (lhs == rhs)
return true;
if (!lhs || !rhs)
return false;
nr = __perf_cpu_map__nr(lhs);
if (nr != __perf_cpu_map__nr(rhs))
return false;
for (int idx = 0; idx < nr; idx++) {
if (__perf_cpu_map__cpu(lhs, idx).cpu != __perf_cpu_map__cpu(rhs, idx).cpu)
return false;
}
return true;
}
bool perf_cpu_map__has_any_cpu(const struct perf_cpu_map *map)
{
return map && __perf_cpu_map__cpu(map, 0).cpu == -1;
}
struct perf_cpu perf_cpu_map__max(const struct perf_cpu_map *map)
{
struct perf_cpu result = {
@ -328,7 +368,9 @@ struct perf_cpu perf_cpu_map__max(const struct perf_cpu_map *map)
};
// cpu_map__trim_new() qsort()s it, cpu_map__default_new() sorts it as well.
return RC_CHK_ACCESS(map)->nr > 0 ? RC_CHK_ACCESS(map)->map[RC_CHK_ACCESS(map)->nr - 1] : result;
return __perf_cpu_map__nr(map) > 0
? __perf_cpu_map__cpu(map, __perf_cpu_map__nr(map) - 1)
: result;
}
/** Is 'b' a subset of 'a'. */
@ -336,15 +378,15 @@ bool perf_cpu_map__is_subset(const struct perf_cpu_map *a, const struct perf_cpu
{
if (a == b || !b)
return true;
if (!a || RC_CHK_ACCESS(b)->nr > RC_CHK_ACCESS(a)->nr)
if (!a || __perf_cpu_map__nr(b) > __perf_cpu_map__nr(a))
return false;
for (int i = 0, j = 0; i < RC_CHK_ACCESS(a)->nr; i++) {
if (RC_CHK_ACCESS(a)->map[i].cpu > RC_CHK_ACCESS(b)->map[j].cpu)
for (int i = 0, j = 0; i < __perf_cpu_map__nr(a); i++) {
if (__perf_cpu_map__cpu(a, i).cpu > __perf_cpu_map__cpu(b, j).cpu)
return false;
if (RC_CHK_ACCESS(a)->map[i].cpu == RC_CHK_ACCESS(b)->map[j].cpu) {
if (__perf_cpu_map__cpu(a, i).cpu == __perf_cpu_map__cpu(b, j).cpu) {
j++;
if (j == RC_CHK_ACCESS(b)->nr)
if (j == __perf_cpu_map__nr(b))
return true;
}
}
@ -374,27 +416,27 @@ struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig,
return perf_cpu_map__get(other);
}
tmp_len = RC_CHK_ACCESS(orig)->nr + RC_CHK_ACCESS(other)->nr;
tmp_len = __perf_cpu_map__nr(orig) + __perf_cpu_map__nr(other);
tmp_cpus = malloc(tmp_len * sizeof(struct perf_cpu));
if (!tmp_cpus)
return NULL;
/* Standard merge algorithm from wikipedia */
i = j = k = 0;
while (i < RC_CHK_ACCESS(orig)->nr && j < RC_CHK_ACCESS(other)->nr) {
if (RC_CHK_ACCESS(orig)->map[i].cpu <= RC_CHK_ACCESS(other)->map[j].cpu) {
if (RC_CHK_ACCESS(orig)->map[i].cpu == RC_CHK_ACCESS(other)->map[j].cpu)
while (i < __perf_cpu_map__nr(orig) && j < __perf_cpu_map__nr(other)) {
if (__perf_cpu_map__cpu(orig, i).cpu <= __perf_cpu_map__cpu(other, j).cpu) {
if (__perf_cpu_map__cpu(orig, i).cpu == __perf_cpu_map__cpu(other, j).cpu)
j++;
tmp_cpus[k++] = RC_CHK_ACCESS(orig)->map[i++];
tmp_cpus[k++] = __perf_cpu_map__cpu(orig, i++);
} else
tmp_cpus[k++] = RC_CHK_ACCESS(other)->map[j++];
tmp_cpus[k++] = __perf_cpu_map__cpu(other, j++);
}
while (i < RC_CHK_ACCESS(orig)->nr)
tmp_cpus[k++] = RC_CHK_ACCESS(orig)->map[i++];
while (i < __perf_cpu_map__nr(orig))
tmp_cpus[k++] = __perf_cpu_map__cpu(orig, i++);
while (j < RC_CHK_ACCESS(other)->nr)
tmp_cpus[k++] = RC_CHK_ACCESS(other)->map[j++];
while (j < __perf_cpu_map__nr(other))
tmp_cpus[k++] = __perf_cpu_map__cpu(other, j++);
assert(k <= tmp_len);
merged = cpu_map__trim_new(k, tmp_cpus);
@ -402,3 +444,38 @@ struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig,
perf_cpu_map__put(orig);
return merged;
}
struct perf_cpu_map *perf_cpu_map__intersect(struct perf_cpu_map *orig,
struct perf_cpu_map *other)
{
struct perf_cpu *tmp_cpus;
int tmp_len;
int i, j, k;
struct perf_cpu_map *merged = NULL;
if (perf_cpu_map__is_subset(other, orig))
return perf_cpu_map__get(orig);
if (perf_cpu_map__is_subset(orig, other))
return perf_cpu_map__get(other);
tmp_len = max(__perf_cpu_map__nr(orig), __perf_cpu_map__nr(other));
tmp_cpus = malloc(tmp_len * sizeof(struct perf_cpu));
if (!tmp_cpus)
return NULL;
i = j = k = 0;
while (i < __perf_cpu_map__nr(orig) && j < __perf_cpu_map__nr(other)) {
if (__perf_cpu_map__cpu(orig, i).cpu < __perf_cpu_map__cpu(other, j).cpu)
i++;
else if (__perf_cpu_map__cpu(orig, i).cpu > __perf_cpu_map__cpu(other, j).cpu)
j++;
else {
j++;
tmp_cpus[k++] = __perf_cpu_map__cpu(orig, i++);
}
}
if (k)
merged = cpu_map__trim_new(k, tmp_cpus);
free(tmp_cpus);
return merged;
}

View File

@ -36,18 +36,33 @@ void perf_evlist__init(struct perf_evlist *evlist)
static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
struct perf_evsel *evsel)
{
/*
* We already have cpus for evsel (via PMU sysfs) so
* keep it, if there's no target cpu list defined.
*/
if (evsel->system_wide) {
/* System wide: set the cpu map of the evsel to all online CPUs. */
perf_cpu_map__put(evsel->cpus);
evsel->cpus = perf_cpu_map__new(NULL);
} else if (evlist->has_user_cpus && evsel->is_pmu_core) {
/*
* User requested CPUs on a core PMU, ensure the requested CPUs
* are valid by intersecting with those of the PMU.
*/
perf_cpu_map__put(evsel->cpus);
evsel->cpus = perf_cpu_map__intersect(evlist->user_requested_cpus, evsel->own_cpus);
} else if (!evsel->own_cpus || evlist->has_user_cpus ||
(!evsel->requires_cpu && perf_cpu_map__empty(evlist->user_requested_cpus))) {
(!evsel->requires_cpu && perf_cpu_map__has_any_cpu(evlist->user_requested_cpus))) {
/*
* The PMU didn't specify a default cpu map, this isn't a core
* event and the user requested CPUs or the evlist user
* requested CPUs have the "any CPU" (aka dummy) CPU value. In
* which case use the user requested CPUs rather than the PMU
* ones.
*/
perf_cpu_map__put(evsel->cpus);
evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
} else if (evsel->cpus != evsel->own_cpus) {
/*
* No user requested cpu map but the PMU cpu map doesn't match
* the evsel's. Reset it back to the PMU cpu map.
*/
perf_cpu_map__put(evsel->cpus);
evsel->cpus = perf_cpu_map__get(evsel->own_cpus);
}

View File

@ -41,7 +41,14 @@ struct perf_sample_id {
struct perf_evsel {
struct list_head node;
struct perf_event_attr attr;
/** The commonly used cpu map of CPUs the event should be opened upon, etc. */
struct perf_cpu_map *cpus;
/**
* The cpu map read from the PMU. For core PMUs this is the list of all
* CPUs the event can be opened upon. For other PMUs this is the default
* cpu map for opening the event on, for example, the first CPU on a
* socket for an uncore event.
*/
struct perf_cpu_map *own_cpus;
struct perf_thread_map *threads;
struct xyarray *fd;
@ -55,9 +62,9 @@ struct perf_evsel {
int nr_members;
/*
* system_wide is for events that need to be on every CPU, irrespective
* of user requested CPUs or threads. Map propagation will set cpus to
* this event's own_cpus, whereby they will contribute to evlist
* all_cpus.
* of user requested CPUs or threads. Tha main example of this is the
* dummy event. Map propagation will set cpus for this event to all CPUs
* as software PMU events like dummy, have a CPU map that is empty.
*/
bool system_wide;
/*
@ -65,6 +72,8 @@ struct perf_evsel {
* i.e. it cannot be the 'any CPU' value of -1.
*/
bool requires_cpu;
/** Is the PMU for the event a core one? Effects the handling of own_cpus. */
bool is_pmu_core;
int idx;
};

View File

@ -11,8 +11,16 @@ struct perf_cpu {
int cpu;
};
struct perf_cache {
int cache_lvl;
int cache;
};
struct perf_cpu_map;
/**
* perf_cpu_map__dummy_new - a map with a singular "any CPU"/dummy -1 value.
*/
LIBPERF_API struct perf_cpu_map *perf_cpu_map__dummy_new(void);
LIBPERF_API struct perf_cpu_map *perf_cpu_map__default_new(void);
LIBPERF_API struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list);
@ -20,12 +28,23 @@ LIBPERF_API struct perf_cpu_map *perf_cpu_map__read(FILE *file);
LIBPERF_API struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map);
LIBPERF_API struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig,
struct perf_cpu_map *other);
LIBPERF_API struct perf_cpu_map *perf_cpu_map__intersect(struct perf_cpu_map *orig,
struct perf_cpu_map *other);
LIBPERF_API void perf_cpu_map__put(struct perf_cpu_map *map);
LIBPERF_API struct perf_cpu perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx);
LIBPERF_API int perf_cpu_map__nr(const struct perf_cpu_map *cpus);
/**
* perf_cpu_map__empty - is map either empty or the "any CPU"/dummy value.
*/
LIBPERF_API bool perf_cpu_map__empty(const struct perf_cpu_map *map);
LIBPERF_API struct perf_cpu perf_cpu_map__max(const struct perf_cpu_map *map);
LIBPERF_API bool perf_cpu_map__has(const struct perf_cpu_map *map, struct perf_cpu cpu);
LIBPERF_API bool perf_cpu_map__equal(const struct perf_cpu_map *lhs,
const struct perf_cpu_map *rhs);
/**
* perf_cpu_map__any_cpu - Does the map contain the "any CPU"/dummy -1 value?
*/
LIBPERF_API bool perf_cpu_map__has_any_cpu(const struct perf_cpu_map *map);
#define perf_cpu_map__for_each_cpu(cpu, idx, cpus) \
for ((idx) = 0, (cpu) = perf_cpu_map__cpu(cpus, idx); \

View File

@ -380,7 +380,8 @@ enum {
PERF_STAT_CONFIG_TERM__AGGR_MODE = 0,
PERF_STAT_CONFIG_TERM__INTERVAL = 1,
PERF_STAT_CONFIG_TERM__SCALE = 2,
PERF_STAT_CONFIG_TERM__MAX = 3,
PERF_STAT_CONFIG_TERM__AGGR_LEVEL = 3,
PERF_STAT_CONFIG_TERM__MAX = 4,
};
struct perf_record_stat_config_entry {

View File

@ -36,38 +36,40 @@ static int is_absolute_path(const char *path)
return path[0] == '/';
}
static const char *get_pwd_cwd(void)
static const char *get_pwd_cwd(char *buf, size_t sz)
{
static char cwd[PATH_MAX + 1];
char *pwd;
struct stat cwd_stat, pwd_stat;
if (getcwd(cwd, PATH_MAX) == NULL)
if (getcwd(buf, sz) == NULL)
return NULL;
pwd = getenv("PWD");
if (pwd && strcmp(pwd, cwd)) {
stat(cwd, &cwd_stat);
if (pwd && strcmp(pwd, buf)) {
stat(buf, &cwd_stat);
if (!stat(pwd, &pwd_stat) &&
pwd_stat.st_dev == cwd_stat.st_dev &&
pwd_stat.st_ino == cwd_stat.st_ino) {
strlcpy(cwd, pwd, PATH_MAX);
strlcpy(buf, pwd, sz);
}
}
return cwd;
return buf;
}
static const char *make_nonrelative_path(const char *path)
static const char *make_nonrelative_path(char *buf, size_t sz, const char *path)
{
static char buf[PATH_MAX + 1];
if (is_absolute_path(path)) {
if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
if (strlcpy(buf, path, sz) >= sz)
die("Too long path: %.*s", 60, path);
} else {
const char *cwd = get_pwd_cwd();
const char *cwd = get_pwd_cwd(buf, sz);
if (!cwd)
die("Cannot determine the current working directory");
if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX)
if (strlen(cwd) + strlen(path) + 2 >= sz)
die("Too long path: %.*s", 60, path);
strcat(buf, "/");
strcat(buf, path);
}
return buf;
}
@ -133,8 +135,11 @@ static void add_path(char **out, const char *path)
if (path && *path) {
if (is_absolute_path(path))
astrcat(out, path);
else
astrcat(out, make_nonrelative_path(path));
else {
char buf[PATH_MAX];
astrcat(out, make_nonrelative_path(buf, sizeof(buf), path));
}
astrcat(out, ":");
}

View File

@ -16,6 +16,8 @@
void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
{
struct cmdname *ent = malloc(sizeof(*ent) + len + 1);
if (!ent)
return;
ent->len = len;
memcpy(ent->name, name, len);
@ -66,6 +68,7 @@ void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
while (ci < cmds->cnt && ei < excludes->cnt) {
cmp = strcmp(cmds->names[ci]->name, excludes->names[ei]->name);
if (cmp < 0) {
zfree(&cmds->names[cj]);
cmds->names[cj++] = cmds->names[ci++];
} else if (cmp == 0) {
ci++;
@ -75,9 +78,12 @@ void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
}
}
while (ci < cmds->cnt)
while (ci < cmds->cnt) {
zfree(&cmds->names[cj]);
cmds->names[cj++] = cmds->names[ci++];
}
for (ci = cj; ci < cmds->cnt; ci++)
zfree(&cmds->names[ci]);
cmds->cnt = cj;
}

View File

@ -250,11 +250,20 @@ $(MAN_HTML): $(OUTPUT)%.html : %.txt
$(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) -o $@+ $< && \
mv $@+ $@
# Generate date from either KBUILD_BUILD_TIMESTAMP or git log of
# the doc input file
PERF_DATE = $(strip \
$(if $(KBUILD_BUILD_TIMESTAMP), \
$(shell date -u -d '$(KBUILD_BUILD_TIMESTAMP)' +%Y-%m-%d), \
$(shell git log -1 --pretty="format:%cd" \
--date=short --no-show-signature $<)))
ifdef USE_ASCIIDOCTOR
$(OUTPUT)%.1 $(OUTPUT)%.5 $(OUTPUT)%.7 : %.txt
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
$(ASCIIDOC) -b manpage -d manpage \
$(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) -o $@+ $< && \
$(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) \
-adocdate=$(PERF_DATE) -o $@+ $< && \
mv $@+ $@
endif
@ -266,9 +275,7 @@ $(OUTPUT)%.xml : %.txt
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
$(ASCIIDOC) -b docbook -d manpage \
$(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) \
-aperf_date=$(shell git log -1 --pretty="format:%cd" \
--date=short --no-show-signature $<) \
-o $@+ $< && \
-aperf_date=$(PERF_DATE) -o $@+ $< && \
mv $@+ $@
XSLT = docbook.xsl

View File

@ -130,7 +130,7 @@ OPTIONS
-F::
--fields::
Comma separated list of fields to print. Options are:
comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff,
comm, tid, pid, time, cpu, event, trace, ip, sym, dso, dsoff, addr, symoff,
srcline, period, iregs, uregs, brstack, brstacksym, flags, bpf-output,
brstackinsn, brstackinsnlen, brstackoff, callindent, insn, insnlen, synth,
phys_addr, metric, misc, srccode, ipc, data_page_size, code_page_size, ins_lat,

View File

@ -308,6 +308,14 @@ use --per-die in addition to -a. (system-wide). The output includes the
die number and the number of online processors on that die. This is
useful to gauge the amount of aggregation.
--per-cache::
Aggregate counts per cache instance for system-wide mode measurements. By
default, the aggregation happens for the cache level at the highest index
in the system. To specify a particular level, mention the cache level
alongside the option in the format [Ll][1-9][0-9]*. For example:
Using option "--per-cache=l3" or "--per-cache=L3" will aggregate the
information at the boundary of the level 3 cache in the system.
--per-core::
Aggregate counts per physical processor for system-wide mode measurements. This
is a useful mode to detect imbalance between physical cores. To enable this mode,
@ -353,6 +361,15 @@ small group that need not have multiplexing is lowered. This option
forbids the event merging logic from sharing events between groups and
may be used to increase accuracy in this case.
--metric-no-threshold::
Metric thresholds may increase the number of events necessary to
compute whether a metric has exceeded its threshold expression. This
may not be desirable, for example, as the events can introduce
multiplexing. This option disables the adding of threshold expression
events for a metric. However, if there are sufficient events to
compute the threshold then the threshold is still computed and used to
color the metric's computed value.
--quiet::
Don't print output, warnings or messages. This is useful with perf stat
record below to only write data to the perf.data file.
@ -379,6 +396,14 @@ Aggregate counts per processor socket for system-wide mode measurements.
--per-die::
Aggregate counts per processor die for system-wide mode measurements.
--per-cache::
Aggregate counts per cache instance for system-wide mode measurements. By
default, the aggregation happens for the cache level at the highest index
in the system. To specify a particular level, mention the cache level
alongside the option in the format [Ll][1-9][0-9]*. For example: Using
option "--per-cache=l3" or "--per-cache=L3" will aggregate the
information at the boundary of the level 3 cache in the system.
--per-core::
Aggregate counts per physical processor for system-wide mode measurements.
@ -389,6 +414,12 @@ For a group all metrics from the group are added.
The events from the metrics are automatically measured.
See perf list output for the possible metrics and metricgroups.
When threshold information is available for a metric, the
color red is used to signify a metric has exceeded a threshold
while green shows it hasn't. The default color means that
no threshold information was available or the threshold
couldn't be computed.
-A::
--no-aggr::
Do not aggregate counts across all monitored CPUs.

View File

@ -1075,6 +1075,11 @@ ifndef NO_AUXTRACE
endif
endif
ifdef EXTRA_TESTS
$(call detected,CONFIG_EXTRA_TESTS)
CFLAGS += -DHAVE_EXTRA_TESTS
endif
ifndef NO_JVMTI
ifneq (,$(wildcard /usr/sbin/update-java-alternatives))
JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | awk '{print $$3}')

View File

@ -128,6 +128,10 @@ include ../scripts/utilities.mak
#
# Define BUILD_NONDISTRO to enable building an linking against libbfd and
# libiberty distribution license incompatible libraries.
#
# Define EXTRA_TESTS to enable building extra tests useful mainly to perf
# developers, such as:
# x86 instruction decoder - new instructions test
# As per kernel Makefile, avoid funny character set dependencies
unexport LC_ALL

View File

@ -26,7 +26,7 @@ static int sample_ustack(struct perf_sample *sample,
sp = (unsigned long) regs[PERF_REG_ARM_SP];
map = maps__find(thread->maps, (u64)sp);
map = maps__find(thread__maps(thread), (u64)sp);
if (!map) {
pr_debug("failed to get stack map\n");
free(buf);

View File

@ -14,6 +14,7 @@
#include "../../../util/debug.h"
#include "../../../util/evlist.h"
#include "../../../util/pmu.h"
#include "../../../util/pmus.h"
#include "cs-etm.h"
#include "arm-spe.h"
#include "hisi-ptt.h"
@ -40,7 +41,7 @@ static struct perf_pmu **find_all_arm_spe_pmus(int *nr_spes, int *err)
return NULL;
}
arm_spe_pmus[*nr_spes] = perf_pmu__find(arm_spe_pmu_name);
arm_spe_pmus[*nr_spes] = perf_pmus__find(arm_spe_pmu_name);
if (arm_spe_pmus[*nr_spes]) {
pr_debug2("%s %d: arm_spe_pmu %d type %d name %s\n",
__func__, __LINE__, *nr_spes,
@ -87,7 +88,7 @@ static struct perf_pmu **find_all_hisi_ptt_pmus(int *nr_ptts, int *err)
rewinddir(dir);
while ((dent = readdir(dir))) {
if (strstr(dent->d_name, HISI_PTT_PMU_NAME) && idx < *nr_ptts) {
hisi_ptt_pmus[idx] = perf_pmu__find(dent->d_name);
hisi_ptt_pmus[idx] = perf_pmus__find(dent->d_name);
if (hisi_ptt_pmus[idx])
idx++;
}
@ -131,7 +132,7 @@ struct auxtrace_record
if (!evlist)
return NULL;
cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME);
cs_etm_pmu = perf_pmus__find(CORESIGHT_ETM_PMU_NAME);
arm_spe_pmus = find_all_arm_spe_pmus(&nr_spes, err);
hisi_ptt_pmus = find_all_hisi_ptt_pmus(&nr_ptts, err);

View File

@ -25,7 +25,7 @@
#include "../../../util/evsel.h"
#include "../../../util/perf_api_probe.h"
#include "../../../util/evsel_config.h"
#include "../../../util/pmu.h"
#include "../../../util/pmus.h"
#include "../../../util/cs-etm.h"
#include <internal/lib.h> // page_size
#include "../../../util/session.h"
@ -881,7 +881,7 @@ struct auxtrace_record *cs_etm_record_init(int *err)
struct perf_pmu *cs_etm_pmu;
struct cs_etm_recording *ptr;
cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME);
cs_etm_pmu = perf_pmus__find(CORESIGHT_ETM_PMU_NAME);
if (!cs_etm_pmu) {
*err = -EINVAL;

View File

@ -19,27 +19,28 @@ if ! test -r $input; then
exit 1
fi
create_table_from_c()
create_sc_table()
{
local sc nr last_sc
local sc nr max_nr
while read sc nr; do
printf "%s\n" " [$nr] = \"$sc\","
last_sc=$sc
max_nr=$nr
done
printf "%s\n" "#define SYSCALLTBL_ARM64_MAX_ID __NR_$last_sc"
echo "#define SYSCALLTBL_ARM64_MAX_ID $max_nr"
}
create_table()
{
echo "#include \"$input\""
echo "static const char *syscalltbl_arm64[] = {"
create_table_from_c
echo "static const char *const syscalltbl_arm64[] = {"
create_sc_table
echo "};"
}
$gcc -E -dM -x c -I $incpath/include/uapi $input \
|sed -ne 's/^#define __NR_//p' \
|sort -t' ' -k2 -n \
|awk '$2 ~ "__NR" && $3 !~ "__NR3264_" {
sub("^#define __NR(3264)?_", "");
print | "sort -k2 -n"}' \
|create_table

View File

@ -26,7 +26,7 @@ static int sample_ustack(struct perf_sample *sample,
sp = (unsigned long) regs[PERF_REG_ARM64_SP];
map = maps__find(thread->maps, (u64)sp);
map = maps__find(thread__maps(thread), (u64)sp);
if (!map) {
pr_debug("failed to get stack map\n");
free(buf);

View File

@ -3,6 +3,7 @@
#include <internal/cpumap.h>
#include "../../../util/cpumap.h"
#include "../../../util/pmu.h"
#include "../../../util/pmus.h"
#include <api/fs/fs.h>
#include <math.h>
@ -10,10 +11,7 @@ static struct perf_pmu *pmu__find_core_pmu(void)
{
struct perf_pmu *pmu = NULL;
while ((pmu = perf_pmu__scan(pmu))) {
if (!is_pmu_core(pmu->name))
continue;
while ((pmu = perf_pmus__scan_core(pmu))) {
/*
* The cpumap should cover all CPUs. Otherwise, some CPUs may
* not support some events or have different event IDs.

View File

@ -43,6 +43,20 @@ const char *const powerpc_triplets[] = {
NULL
};
const char *const riscv32_triplets[] = {
"riscv32-unknown-linux-gnu-",
"riscv32-linux-android-",
"riscv32-linux-gnu-",
NULL
};
const char *const riscv64_triplets[] = {
"riscv64-unknown-linux-gnu-",
"riscv64-linux-android-",
"riscv64-linux-gnu-",
NULL
};
const char *const s390_triplets[] = {
"s390-ibm-linux-",
"s390x-linux-gnu-",
@ -164,6 +178,10 @@ static int perf_env__lookup_binutils_path(struct perf_env *env,
path_list = arm64_triplets;
else if (!strcmp(arch, "powerpc"))
path_list = powerpc_triplets;
else if (!strcmp(arch, "riscv32"))
path_list = riscv32_triplets;
else if (!strcmp(arch, "riscv64"))
path_list = riscv64_triplets;
else if (!strcmp(arch, "sh"))
path_list = sh_triplets;
else if (!strcmp(arch, "s390"))

View File

@ -5,25 +5,115 @@
* Copyright (C) 2020-2023 Loongson Technology Corporation Limited
*/
static int loongarch_call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
{
char *c, *endptr, *tok, *name;
struct map *map = ms->map;
struct addr_map_symbol target = {
.ms = { .map = map, },
};
c = strchr(ops->raw, '#');
if (c++ == NULL)
return -1;
ops->target.addr = strtoull(c, &endptr, 16);
name = strchr(endptr, '<');
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 (maps__find_ams(ms->maps, &target) == 0 &&
map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
ops->target.sym = target.ms.sym;
return 0;
}
static struct ins_ops loongarch_call_ops = {
.parse = loongarch_call__parse,
.scnprintf = call__scnprintf,
};
static int loongarch_jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
{
struct map *map = ms->map;
struct symbol *sym = ms->sym;
struct addr_map_symbol target = {
.ms = { .map = map, },
};
const char *c = strchr(ops->raw, '#');
u64 start, end;
ops->raw_comment = strchr(ops->raw, arch->objdump.comment_char);
ops->raw_func_start = strchr(ops->raw, '<');
if (ops->raw_func_start && c > ops->raw_func_start)
c = NULL;
if (c++ != NULL)
ops->target.addr = strtoull(c, NULL, 16);
else
ops->target.addr = strtoull(ops->raw, NULL, 16);
target.addr = map__objdump_2mem(map, ops->target.addr);
start = map__unmap_ip(map, sym->start);
end = map__unmap_ip(map, sym->end);
ops->target.outside = target.addr < start || target.addr > end;
if (maps__find_ams(ms->maps, &target) == 0 &&
map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
ops->target.sym = target.ms.sym;
if (!ops->target.outside) {
ops->target.offset = target.addr - start;
ops->target.offset_avail = true;
} else {
ops->target.offset_avail = false;
}
return 0;
}
static struct ins_ops loongarch_jump_ops = {
.parse = loongarch_jump__parse,
.scnprintf = jump__scnprintf,
};
static
struct ins_ops *loongarch__associate_ins_ops(struct arch *arch, const char *name)
{
struct ins_ops *ops = NULL;
if (!strncmp(name, "beqz", 4) ||
!strncmp(name, "bnez", 4) ||
!strncmp(name, "beq", 3) ||
!strncmp(name, "bne", 3) ||
!strncmp(name, "blt", 3) ||
!strncmp(name, "bge", 3) ||
!strncmp(name, "bltu", 4) ||
!strncmp(name, "bgeu", 4) ||
!strncmp(name, "bl", 2))
ops = &call_ops;
else if (!strncmp(name, "jirl", 4))
if (!strcmp(name, "bl"))
ops = &loongarch_call_ops;
else if (!strcmp(name, "jirl"))
ops = &ret_ops;
else if (name[0] == 'b')
ops = &jump_ops;
else if (!strcmp(name, "b") ||
!strncmp(name, "beq", 3) ||
!strncmp(name, "bne", 3) ||
!strncmp(name, "blt", 3) ||
!strncmp(name, "bge", 3) ||
!strncmp(name, "bltu", 4) ||
!strncmp(name, "bgeu", 4))
ops = &loongarch_jump_ops;
else
return NULL;

View File

@ -18,44 +18,28 @@ if ! test -r $input; then
exit 1
fi
create_table_from_c()
create_sc_table()
{
local sc nr last_sc
create_table_exe=`mktemp ${TMPDIR:-/tmp}/create-table-XXXXXX`
{
cat <<-_EoHEADER
#include <stdio.h>
#include "$input"
int main(int argc, char *argv[])
{
_EoHEADER
local sc nr max_nr
while read sc nr; do
printf "%s\n" " printf(\"\\t[%d] = \\\"$sc\\\",\\n\", $nr);"
last_sc=$nr
printf "%s\n" " [$nr] = \"$sc\","
max_nr=$nr
done
printf "%s\n" " printf(\"#define SYSCALLTBL_LOONGARCH_MAX_ID %d\\n\", $last_sc);"
printf "}\n"
} | $hostcc -I $incpath/include/uapi -o $create_table_exe -x c -
$create_table_exe
rm -f $create_table_exe
echo "#define SYSCALLTBL_LOONGARCH_MAX_ID $max_nr"
}
create_table()
{
echo "static const char *syscalltbl_loongarch[] = {"
create_table_from_c
echo "#include \"$input\""
echo "static const char *const syscalltbl_loongarch[] = {"
create_sc_table
echo "};"
}
$gcc -E -dM -x c -I $incpath/include/uapi $input \
|sed -ne 's/^#define __NR_//p' \
|sort -t' ' -k2 -n \
$gcc -E -dM -x c -I $incpath/include/uapi $input \
|awk '$2 ~ "__NR" && $3 !~ "__NR3264_" {
sub("^#define __NR(3264)?_", "");
print | "sort -k2 -n"}' \
|create_table

View File

@ -18,7 +18,7 @@ create_table()
{
local max_nr nr abi sc discard
echo 'static const char *syscalltbl_mips_n64[] = {'
echo 'static const char *const syscalltbl_mips_n64[] = {'
while read nr abi sc discard; do
printf '\t[%d] = "%s",\n' $nr $sc
max_nr=$nr

View File

@ -23,7 +23,7 @@ create_table()
max_nr=-1
nr=0
echo "static const char *syscalltbl_powerpc_${wordsize}[] = {"
echo "static const char *const syscalltbl_powerpc_${wordsize}[] = {"
while read nr abi sc discard; do
if [ "$max_nr" -lt "$nr" ]; then
printf '\t[%d] = "%s",\n' $nr $sc

View File

@ -26,7 +26,7 @@ static int sample_ustack(struct perf_sample *sample,
sp = (unsigned long) regs[PERF_REG_POWERPC_R1];
map = maps__find(thread->maps, (u64)sp);
map = maps__find(thread__maps(thread), (u64)sp);
if (!map) {
pr_debug("failed to get stack map\n");
free(buf);

View File

@ -5,7 +5,7 @@
#include "util/debug.h"
#include "util/evsel.h"
#include "util/evlist.h"
#include "util/pmu.h"
#include "util/pmus.h"
#include "book3s_hv_exits.h"
#include "book3s_hcalls.h"
@ -204,7 +204,7 @@ int kvm_add_default_arch_event(int *argc, const char **argv)
parse_options(j, tmp, event_options, NULL, PARSE_OPT_KEEP_UNKNOWN);
if (!event) {
if (pmu_have_event("trace_imc", "trace_cycles")) {
if (perf_pmus__have_event("trace_imc", "trace_cycles")) {
argv[j++] = strdup("-e");
argv[j++] = strdup("trace_imc/trace_cycles/");
*argc += 2;

View File

@ -45,9 +45,6 @@ static int s390_call__parse(struct arch *arch, struct ins_operands *ops,
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,

View File

@ -18,7 +18,7 @@ create_table()
{
local max_nr nr abi sc discard
echo 'static const char *syscalltbl_s390_64[] = {'
echo 'static const char *const syscalltbl_s390_64[] = {'
while read nr abi sc discard; do
printf '\t[%d] = "%s",\n' $nr $sc
max_nr=$nr

View File

@ -1,46 +1,37 @@
// SPDX-License-Identifier: GPL-2.0
/*
* x86 instruction nmemonic table to parse disasm lines for annotate.
* This table is searched twice - one for exact match and another for
* match without a size suffix (b, w, l, q) in case of AT&T syntax.
*
* So this table should not have entries with the suffix unless it's
* a complete different instruction than ones without the suffix.
*/
static struct ins x86__instructions[] = {
{ .name = "adc", .ops = &mov_ops, },
{ .name = "adcb", .ops = &mov_ops, },
{ .name = "adcl", .ops = &mov_ops, },
{ .name = "add", .ops = &mov_ops, },
{ .name = "addl", .ops = &mov_ops, },
{ .name = "addq", .ops = &mov_ops, },
{ .name = "addsd", .ops = &mov_ops, },
{ .name = "addw", .ops = &mov_ops, },
{ .name = "and", .ops = &mov_ops, },
{ .name = "andb", .ops = &mov_ops, },
{ .name = "andl", .ops = &mov_ops, },
{ .name = "andpd", .ops = &mov_ops, },
{ .name = "andps", .ops = &mov_ops, },
{ .name = "andq", .ops = &mov_ops, },
{ .name = "andw", .ops = &mov_ops, },
{ .name = "bsr", .ops = &mov_ops, },
{ .name = "bt", .ops = &mov_ops, },
{ .name = "btr", .ops = &mov_ops, },
{ .name = "bts", .ops = &mov_ops, },
{ .name = "btsq", .ops = &mov_ops, },
{ .name = "call", .ops = &call_ops, },
{ .name = "callq", .ops = &call_ops, },
{ .name = "cmovbe", .ops = &mov_ops, },
{ .name = "cmove", .ops = &mov_ops, },
{ .name = "cmovae", .ops = &mov_ops, },
{ .name = "cmp", .ops = &mov_ops, },
{ .name = "cmpb", .ops = &mov_ops, },
{ .name = "cmpl", .ops = &mov_ops, },
{ .name = "cmpq", .ops = &mov_ops, },
{ .name = "cmpw", .ops = &mov_ops, },
{ .name = "cmpxch", .ops = &mov_ops, },
{ .name = "cmpxchg", .ops = &mov_ops, },
{ .name = "cs", .ops = &mov_ops, },
{ .name = "dec", .ops = &dec_ops, },
{ .name = "decl", .ops = &dec_ops, },
{ .name = "divsd", .ops = &mov_ops, },
{ .name = "divss", .ops = &mov_ops, },
{ .name = "gs", .ops = &mov_ops, },
{ .name = "imul", .ops = &mov_ops, },
{ .name = "inc", .ops = &dec_ops, },
{ .name = "incl", .ops = &dec_ops, },
{ .name = "ja", .ops = &jump_ops, },
{ .name = "jae", .ops = &jump_ops, },
{ .name = "jb", .ops = &jump_ops, },
@ -54,7 +45,6 @@ static struct ins x86__instructions[] = {
{ .name = "jl", .ops = &jump_ops, },
{ .name = "jle", .ops = &jump_ops, },
{ .name = "jmp", .ops = &jump_ops, },
{ .name = "jmpq", .ops = &jump_ops, },
{ .name = "jna", .ops = &jump_ops, },
{ .name = "jnae", .ops = &jump_ops, },
{ .name = "jnb", .ops = &jump_ops, },
@ -81,48 +71,32 @@ static struct ins x86__instructions[] = {
{ .name = "mov", .ops = &mov_ops, },
{ .name = "movapd", .ops = &mov_ops, },
{ .name = "movaps", .ops = &mov_ops, },
{ .name = "movb", .ops = &mov_ops, },
{ .name = "movdqa", .ops = &mov_ops, },
{ .name = "movdqu", .ops = &mov_ops, },
{ .name = "movl", .ops = &mov_ops, },
{ .name = "movq", .ops = &mov_ops, },
{ .name = "movsd", .ops = &mov_ops, },
{ .name = "movslq", .ops = &mov_ops, },
{ .name = "movss", .ops = &mov_ops, },
{ .name = "movupd", .ops = &mov_ops, },
{ .name = "movups", .ops = &mov_ops, },
{ .name = "movw", .ops = &mov_ops, },
{ .name = "movzbl", .ops = &mov_ops, },
{ .name = "movzwl", .ops = &mov_ops, },
{ .name = "mulsd", .ops = &mov_ops, },
{ .name = "mulss", .ops = &mov_ops, },
{ .name = "nop", .ops = &nop_ops, },
{ .name = "nopl", .ops = &nop_ops, },
{ .name = "nopw", .ops = &nop_ops, },
{ .name = "or", .ops = &mov_ops, },
{ .name = "orb", .ops = &mov_ops, },
{ .name = "orl", .ops = &mov_ops, },
{ .name = "orps", .ops = &mov_ops, },
{ .name = "orq", .ops = &mov_ops, },
{ .name = "pand", .ops = &mov_ops, },
{ .name = "paddq", .ops = &mov_ops, },
{ .name = "pcmpeqb", .ops = &mov_ops, },
{ .name = "por", .ops = &mov_ops, },
{ .name = "rclb", .ops = &mov_ops, },
{ .name = "rcll", .ops = &mov_ops, },
{ .name = "rcl", .ops = &mov_ops, },
{ .name = "ret", .ops = &ret_ops, },
{ .name = "retq", .ops = &ret_ops, },
{ .name = "sbb", .ops = &mov_ops, },
{ .name = "sbbl", .ops = &mov_ops, },
{ .name = "sete", .ops = &mov_ops, },
{ .name = "sub", .ops = &mov_ops, },
{ .name = "subl", .ops = &mov_ops, },
{ .name = "subq", .ops = &mov_ops, },
{ .name = "subsd", .ops = &mov_ops, },
{ .name = "subw", .ops = &mov_ops, },
{ .name = "test", .ops = &mov_ops, },
{ .name = "testb", .ops = &mov_ops, },
{ .name = "testl", .ops = &mov_ops, },
{ .name = "tzcnt", .ops = &mov_ops, },
{ .name = "ucomisd", .ops = &mov_ops, },
{ .name = "ucomiss", .ops = &mov_ops, },
{ .name = "vaddsd", .ops = &mov_ops, },
@ -135,11 +109,9 @@ static struct ins x86__instructions[] = {
{ .name = "vsubsd", .ops = &mov_ops, },
{ .name = "vucomisd", .ops = &mov_ops, },
{ .name = "xadd", .ops = &mov_ops, },
{ .name = "xbeginl", .ops = &jump_ops, },
{ .name = "xbeginq", .ops = &jump_ops, },
{ .name = "xbegin", .ops = &jump_ops, },
{ .name = "xchg", .ops = &mov_ops, },
{ .name = "xor", .ops = &mov_ops, },
{ .name = "xorb", .ops = &mov_ops, },
{ .name = "xorpd", .ops = &mov_ops, },
{ .name = "xorps", .ops = &mov_ops, },
};

View File

@ -18,7 +18,7 @@ emit() {
syscall_macro "$nr" "$entry"
}
echo "static const char *syscalltbl_${arch}[] = {"
echo "static const char *const syscalltbl_${arch}[] = {"
sorted_table=$(mktemp /tmp/syscalltbl.XXXXXX)
grep '^[0-9]' "$in" | sort -n > $sorted_table

View File

@ -6,12 +6,15 @@ struct test_suite;
/* Tests */
int test__rdpmc(struct test_suite *test, int subtest);
#ifdef HAVE_EXTRA_TESTS
int test__insn_x86(struct test_suite *test, int subtest);
#endif
int test__intel_pt_pkt_decoder(struct test_suite *test, int subtest);
int test__intel_pt_hybrid_compat(struct test_suite *test, int subtest);
int test__bp_modify(struct test_suite *test, int subtest);
int test__x86_sample_parsing(struct test_suite *test, int subtest);
int test__amd_ibs_via_core_pmu(struct test_suite *test, int subtest);
int test__hybrid(struct test_suite *test, int subtest);
extern struct test_suite *arch_tests[];

View File

@ -3,6 +3,10 @@ perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
perf-y += arch-tests.o
perf-y += sample-parsing.o
perf-$(CONFIG_AUXTRACE) += insn-x86.o intel-pt-test.o
perf-y += hybrid.o
perf-$(CONFIG_AUXTRACE) += intel-pt-test.o
ifeq ($(CONFIG_EXTRA_TESTS),y)
perf-$(CONFIG_AUXTRACE) += insn-x86.o
endif
perf-$(CONFIG_X86_64) += bp-modify.o
perf-y += amd-ibs-via-core-pmu.o

View File

@ -44,10 +44,7 @@ int test__amd_ibs_via_core_pmu(struct test_suite *test __maybe_unused,
int ret = TEST_OK;
int fd, i;
if (list_empty(&pmus))
perf_pmu__scan(NULL);
ibs_pmu = perf_pmu__find("ibs_op");
ibs_pmu = perf_pmus__find("ibs_op");
if (!ibs_pmu)
return TEST_SKIP;

View File

@ -4,7 +4,9 @@
#include "arch-tests.h"
#ifdef HAVE_AUXTRACE_SUPPORT
#ifdef HAVE_EXTRA_TESTS
DEFINE_SUITE("x86 instruction decoder - new instructions", insn_x86);
#endif
static struct test_case intel_pt_tests[] = {
TEST_CASE("Intel PT packet decoder", intel_pt_pkt_decoder),
@ -23,13 +25,24 @@ DEFINE_SUITE("x86 bp modify", bp_modify);
#endif
DEFINE_SUITE("x86 Sample parsing", x86_sample_parsing);
DEFINE_SUITE("AMD IBS via core pmu", amd_ibs_via_core_pmu);
static struct test_case hybrid_tests[] = {
TEST_CASE_REASON("x86 hybrid event parsing", hybrid, "not hybrid"),
{ .name = NULL, }
};
struct test_suite suite__hybrid = {
.desc = "x86 hybrid",
.test_cases = hybrid_tests,
};
struct test_suite *arch_tests[] = {
#ifdef HAVE_DWARF_UNWIND_SUPPORT
&suite__dwarf_unwind,
#endif
#ifdef HAVE_AUXTRACE_SUPPORT
#ifdef HAVE_EXTRA_TESTS
&suite__insn_x86,
#endif
&suite__intel_pt,
#endif
#if defined(__x86_64__)
@ -37,5 +50,6 @@ struct test_suite *arch_tests[] = {
#endif
&suite__x86_sample_parsing,
&suite__amd_ibs_via_core_pmu,
&suite__hybrid,
NULL,
};

View File

@ -26,7 +26,7 @@ static int sample_ustack(struct perf_sample *sample,
sp = (unsigned long) regs[PERF_REG_X86_SP];
map = maps__find(thread->maps, (u64)sp);
map = maps__find(thread__maps(thread), (u64)sp);
if (!map) {
pr_debug("failed to get stack map\n");
free(buf);

View File

@ -0,0 +1,288 @@
// SPDX-License-Identifier: GPL-2.0
#include "arch-tests.h"
#include "debug.h"
#include "evlist.h"
#include "evsel.h"
#include "pmu.h"
#include "pmus.h"
#include "tests/tests.h"
static bool test_config(const struct evsel *evsel, __u64 expected_config)
{
return (evsel->core.attr.config & PERF_HW_EVENT_MASK) == expected_config;
}
static bool test_perf_config(const struct perf_evsel *evsel, __u64 expected_config)
{
return (evsel->attr.config & PERF_HW_EVENT_MASK) == expected_config;
}
static bool test_hybrid_type(const struct evsel *evsel, __u64 expected_config)
{
return (evsel->core.attr.config >> PERF_PMU_TYPE_SHIFT) == expected_config;
}
static int test__hybrid_hw_event_with_pmu(struct evlist *evlist)
{
struct evsel *evsel = evlist__first(evlist);
TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW));
TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
return TEST_OK;
}
static int test__hybrid_hw_group_event(struct evlist *evlist)
{
struct evsel *evsel, *leader;
evsel = leader = evlist__first(evlist);
TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW));
TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
evsel = evsel__next(evsel);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW));
TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS));
TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
return TEST_OK;
}
static int test__hybrid_sw_hw_group_event(struct evlist *evlist)
{
struct evsel *evsel, *leader;
evsel = leader = evlist__first(evlist);
TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type);
TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
evsel = evsel__next(evsel);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW));
TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
return TEST_OK;
}
static int test__hybrid_hw_sw_group_event(struct evlist *evlist)
{
struct evsel *evsel, *leader;
evsel = leader = evlist__first(evlist);
TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW));
TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
evsel = evsel__next(evsel);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type);
TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
return TEST_OK;
}
static int test__hybrid_group_modifier1(struct evlist *evlist)
{
struct evsel *evsel, *leader;
evsel = leader = evlist__first(evlist);
TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW));
TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user);
TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
evsel = evsel__next(evsel);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW));
TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS));
TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
return TEST_OK;
}
static int test__hybrid_raw1(struct evlist *evlist)
{
struct perf_evsel *evsel;
perf_evlist__for_each_evsel(&evlist->core, evsel) {
struct perf_pmu *pmu = perf_pmus__find_by_type(evsel->attr.type);
TEST_ASSERT_VAL("missing pmu", pmu);
TEST_ASSERT_VAL("unexpected pmu", !strncmp(pmu->name, "cpu_", 4));
TEST_ASSERT_VAL("wrong config", test_perf_config(evsel, 0x1a));
}
return TEST_OK;
}
static int test__hybrid_raw2(struct evlist *evlist)
{
struct evsel *evsel = evlist__first(evlist);
TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type);
TEST_ASSERT_VAL("wrong config", test_config(evsel, 0x1a));
return TEST_OK;
}
static int test__hybrid_cache_event(struct evlist *evlist)
{
struct evsel *evsel = evlist__first(evlist);
TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->core.attr.type);
TEST_ASSERT_VAL("wrong config", 0x2 == (evsel->core.attr.config & 0xffffffff));
return TEST_OK;
}
static int test__checkevent_pmu(struct evlist *evlist)
{
struct evsel *evsel = evlist__first(evlist);
TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type);
TEST_ASSERT_VAL("wrong config", 10 == evsel->core.attr.config);
TEST_ASSERT_VAL("wrong config1", 1 == evsel->core.attr.config1);
TEST_ASSERT_VAL("wrong config2", 3 == evsel->core.attr.config2);
TEST_ASSERT_VAL("wrong config3", 0 == evsel->core.attr.config3);
/*
* The period value gets configured within evlist__config,
* while this test executes only parse events method.
*/
TEST_ASSERT_VAL("wrong period", 0 == evsel->core.attr.sample_period);
return TEST_OK;
}
struct evlist_test {
const char *name;
bool (*valid)(void);
int (*check)(struct evlist *evlist);
};
static const struct evlist_test test__hybrid_events[] = {
{
.name = "cpu_core/cpu-cycles/",
.check = test__hybrid_hw_event_with_pmu,
/* 0 */
},
{
.name = "{cpu_core/cpu-cycles/,cpu_core/instructions/}",
.check = test__hybrid_hw_group_event,
/* 1 */
},
{
.name = "{cpu-clock,cpu_core/cpu-cycles/}",
.check = test__hybrid_sw_hw_group_event,
/* 2 */
},
{
.name = "{cpu_core/cpu-cycles/,cpu-clock}",
.check = test__hybrid_hw_sw_group_event,
/* 3 */
},
{
.name = "{cpu_core/cpu-cycles/k,cpu_core/instructions/u}",
.check = test__hybrid_group_modifier1,
/* 4 */
},
{
.name = "r1a",
.check = test__hybrid_raw1,
/* 5 */
},
{
.name = "cpu_core/r1a/",
.check = test__hybrid_raw2,
/* 6 */
},
{
.name = "cpu_core/config=10,config1,config2=3,period=1000/u",
.check = test__checkevent_pmu,
/* 7 */
},
{
.name = "cpu_core/LLC-loads/",
.check = test__hybrid_cache_event,
/* 8 */
},
};
static int test_event(const struct evlist_test *e)
{
struct parse_events_error err;
struct evlist *evlist;
int ret;
if (e->valid && !e->valid()) {
pr_debug("... SKIP\n");
return TEST_OK;
}
evlist = evlist__new();
if (evlist == NULL) {
pr_err("Failed allocation");
return TEST_FAIL;
}
parse_events_error__init(&err);
ret = parse_events(evlist, e->name, &err);
if (ret) {
pr_debug("failed to parse event '%s', err %d, str '%s'\n",
e->name, ret, err.str);
parse_events_error__print(&err, e->name);
ret = TEST_FAIL;
if (strstr(err.str, "can't access trace events"))
ret = TEST_SKIP;
} else {
ret = e->check(evlist);
}
parse_events_error__exit(&err);
evlist__delete(evlist);
return ret;
}
static int combine_test_results(int existing, int latest)
{
if (existing == TEST_FAIL)
return TEST_FAIL;
if (existing == TEST_SKIP)
return latest == TEST_OK ? TEST_SKIP : latest;
return latest;
}
static int test_events(const struct evlist_test *events, int cnt)
{
int ret = TEST_OK;
for (int i = 0; i < cnt; i++) {
const struct evlist_test *e = &events[i];
int test_ret;
pr_debug("running test %d '%s'\n", i, e->name);
test_ret = test_event(e);
if (test_ret != TEST_OK) {
pr_debug("Event test failure: test %d '%s'", i, e->name);
ret = combine_test_results(ret, test_ret);
}
}
return ret;
}
int test__hybrid(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
{
if (perf_pmus__num_core_pmus() == 1)
return TEST_SKIP;
return test_events(test__hybrid_events, ARRAY_SIZE(test__hybrid_events));
}

View File

@ -18,14 +18,14 @@ struct test_data {
const char *asm_rep;
};
struct test_data test_data_32[] = {
const struct test_data test_data_32[] = {
#include "insn-x86-dat-32.c"
{{0x0f, 0x01, 0xee}, 3, 0, NULL, NULL, "0f 01 ee \trdpkru"},
{{0x0f, 0x01, 0xef}, 3, 0, NULL, NULL, "0f 01 ef \twrpkru"},
{{0}, 0, 0, NULL, NULL, NULL},
};
struct test_data test_data_64[] = {
const struct test_data test_data_64[] = {
#include "insn-x86-dat-64.c"
{{0x0f, 0x01, 0xee}, 3, 0, NULL, NULL, "0f 01 ee \trdpkru"},
{{0x0f, 0x01, 0xef}, 3, 0, NULL, NULL, "0f 01 ef \twrpkru"},
@ -97,7 +97,7 @@ static int get_branch(const char *branch_str)
return -1;
}
static int test_data_item(struct test_data *dat, int x86_64)
static int test_data_item(const struct test_data *dat, int x86_64)
{
struct intel_pt_insn intel_pt_insn;
int op, branch, ret;
@ -147,9 +147,9 @@ static int test_data_item(struct test_data *dat, int x86_64)
return 0;
}
static int test_data_set(struct test_data *dat_set, int x86_64)
static int test_data_set(const struct test_data *dat_set, int x86_64)
{
struct test_data *dat;
const struct test_data *dat;
int ret = 0;
for (dat = dat_set; dat->expected_length; dat++) {

View File

@ -22,7 +22,7 @@
* @new_ctx: expected new packet context
* @ctx_unchanged: the packet context must not change
*/
static struct test_data {
static const struct test_data {
int len;
u8 bytes[INTEL_PT_PKT_MAX_SZ];
enum intel_pt_pkt_ctx ctx;
@ -186,7 +186,7 @@ static struct test_data {
{0, {0}, 0, {0, 0, 0}, 0, 0 },
};
static int dump_packet(struct intel_pt_pkt *packet, u8 *bytes, int len)
static int dump_packet(const struct intel_pt_pkt *packet, const u8 *bytes, int len)
{
char desc[INTEL_PT_PKT_DESC_MAX];
int ret, i;
@ -206,14 +206,14 @@ static int dump_packet(struct intel_pt_pkt *packet, u8 *bytes, int len)
return TEST_OK;
}
static void decoding_failed(struct test_data *d)
static void decoding_failed(const struct test_data *d)
{
pr_debug("Decoding failed!\n");
pr_debug("Decoding: ");
dump_packet(&d->packet, d->bytes, d->len);
}
static int fail(struct test_data *d, struct intel_pt_pkt *packet, int len,
static int fail(const struct test_data *d, struct intel_pt_pkt *packet, int len,
enum intel_pt_pkt_ctx new_ctx)
{
decoding_failed(d);
@ -242,7 +242,7 @@ static int fail(struct test_data *d, struct intel_pt_pkt *packet, int len,
return TEST_FAIL;
}
static int test_ctx_unchanged(struct test_data *d, struct intel_pt_pkt *packet,
static int test_ctx_unchanged(const struct test_data *d, struct intel_pt_pkt *packet,
enum intel_pt_pkt_ctx ctx)
{
enum intel_pt_pkt_ctx old_ctx = ctx;
@ -258,7 +258,7 @@ static int test_ctx_unchanged(struct test_data *d, struct intel_pt_pkt *packet,
return TEST_OK;
}
static int test_one(struct test_data *d)
static int test_one(const struct test_data *d)
{
struct intel_pt_pkt packet;
enum intel_pt_pkt_ctx ctx = d->ctx;
@ -307,7 +307,7 @@ static int test_one(struct test_data *d)
*/
int test__intel_pt_pkt_decoder(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
{
struct test_data *d = data;
const struct test_data *d = data;
int ret;
for (d = data; d->len; d++) {

View File

@ -10,6 +10,7 @@ perf-y += evlist.o
perf-y += mem-events.o
perf-y += evsel.o
perf-y += iostat.o
perf-y += env.o
perf-$(CONFIG_DWARF) += dwarf-regs.o
perf-$(CONFIG_BPF_PROLOGUE) += dwarf-regs.o

View File

@ -10,6 +10,7 @@
#include "../../../util/header.h"
#include "../../../util/debug.h"
#include "../../../util/pmu.h"
#include "../../../util/pmus.h"
#include "../../../util/auxtrace.h"
#include "../../../util/intel-pt.h"
#include "../../../util/intel-bts.h"
@ -25,8 +26,8 @@ struct auxtrace_record *auxtrace_record__init_intel(struct evlist *evlist,
bool found_pt = false;
bool found_bts = false;
intel_pt_pmu = perf_pmu__find(INTEL_PT_PMU_NAME);
intel_bts_pmu = perf_pmu__find(INTEL_BTS_PMU_NAME);
intel_pt_pmu = perf_pmus__find(INTEL_PT_PMU_NAME);
intel_bts_pmu = perf_pmus__find(INTEL_BTS_PMU_NAME);
evlist__for_each_entry(evlist, evsel) {
if (intel_pt_pmu && evsel->core.attr.type == intel_pt_pmu->type)

View File

@ -0,0 +1,19 @@
// SPDX-License-Identifier: GPL-2.0
#include "linux/string.h"
#include "util/env.h"
#include "env.h"
bool x86__is_amd_cpu(void)
{
struct perf_env env = { .total_mem = 0, };
static int is_amd; /* 0: Uninitialized, 1: Yes, -1: No */
if (is_amd)
goto ret;
perf_env__cpuid(&env);
is_amd = env.cpuid && strstarts(env.cpuid, "AuthenticAMD") ? 1 : -1;
perf_env__exit(&env);
ret:
return is_amd >= 1 ? true : false;
}

View File

@ -0,0 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _X86_ENV_H
#define _X86_ENV_H
bool x86__is_amd_cpu(void);
#endif /* _X86_ENV_H */

View File

@ -1,38 +1,42 @@
// SPDX-License-Identifier: GPL-2.0
#include <stdio.h>
#include "util/pmu.h"
#include "util/pmus.h"
#include "util/evlist.h"
#include "util/parse-events.h"
#include "util/event.h"
#include "util/pmu-hybrid.h"
#include "topdown.h"
#include "evsel.h"
static int ___evlist__add_default_attrs(struct evlist *evlist,
struct perf_event_attr *attrs,
size_t nr_attrs)
{
struct perf_cpu_map *cpus;
struct evsel *evsel, *n;
struct perf_pmu *pmu;
LIST_HEAD(head);
size_t i = 0;
for (i = 0; i < nr_attrs; i++)
event_attr_init(attrs + i);
if (!perf_pmu__has_hybrid())
if (perf_pmus__num_core_pmus() == 1)
return evlist__add_attrs(evlist, attrs, nr_attrs);
for (i = 0; i < nr_attrs; i++) {
struct perf_pmu *pmu = NULL;
if (attrs[i].type == PERF_TYPE_SOFTWARE) {
evsel = evsel__new(attrs + i);
struct evsel *evsel = evsel__new(attrs + i);
if (evsel == NULL)
goto out_delete_partial_list;
list_add_tail(&evsel->core.node, &head);
continue;
}
perf_pmu__for_each_hybrid_pmu(pmu) {
while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
struct perf_cpu_map *cpus;
struct evsel *evsel;
evsel = evsel__new(attrs + i);
if (evsel == NULL)
goto out_delete_partial_list;
@ -50,8 +54,12 @@ static int ___evlist__add_default_attrs(struct evlist *evlist,
return 0;
out_delete_partial_list:
__evlist__for_each_entry_safe(&head, n, evsel)
evsel__delete(evsel);
{
struct evsel *evsel, *n;
__evlist__for_each_entry_safe(&head, n, evsel)
evsel__delete(evsel);
}
return -1;
}
@ -67,8 +75,7 @@ int arch_evlist__add_default_attrs(struct evlist *evlist,
int arch_evlist__cmp(const struct evsel *lhs, const struct evsel *rhs)
{
if (topdown_sys_has_perf_metrics() &&
(!lhs->pmu_name || !strncmp(lhs->pmu_name, "cpu", 3))) {
if (topdown_sys_has_perf_metrics() && evsel__sys_has_perf_metrics(lhs)) {
/* Ensure the topdown slots comes first. */
if (strcasestr(lhs->name, "slots"))
return -1;

View File

@ -4,9 +4,11 @@
#include "util/evsel.h"
#include "util/env.h"
#include "util/pmu.h"
#include "util/pmus.h"
#include "linux/string.h"
#include "evsel.h"
#include "util/debug.h"
#include "env.h"
#define IBS_FETCH_L3MISSONLY (1ULL << 59)
#define IBS_OP_L3MISSONLY (1ULL << 16)
@ -16,26 +18,6 @@ void arch_evsel__set_sample_weight(struct evsel *evsel)
evsel__set_sample_bit(evsel, WEIGHT_STRUCT);
}
void arch_evsel__fixup_new_cycles(struct perf_event_attr *attr)
{
struct perf_env env = { .total_mem = 0, } ;
if (!perf_env__cpuid(&env))
return;
/*
* On AMD, precise cycles event sampling internally uses IBS pmu.
* But IBS does not have filtering capabilities and perf by default
* sets exclude_guest = 1. This makes IBS pmu event init fail and
* thus perf ends up doing non-precise sampling. Avoid it by clearing
* exclude_guest.
*/
if (env.cpuid && strstarts(env.cpuid, "AuthenticAMD"))
attr->exclude_guest = 0;
free(env.cpuid);
}
/* Check whether the evsel's PMU supports the perf metrics */
bool evsel__sys_has_perf_metrics(const struct evsel *evsel)
{
@ -50,7 +32,7 @@ bool evsel__sys_has_perf_metrics(const struct evsel *evsel)
* should be good enough to detect the perf metrics feature.
*/
if ((evsel->core.attr.type == PERF_TYPE_RAW) &&
pmu_have_event(pmu_name, "slots"))
perf_pmus__have_event(pmu_name, "slots"))
return true;
return false;
@ -97,29 +79,16 @@ void arch__post_evsel_config(struct evsel *evsel, struct perf_event_attr *attr)
{
struct perf_pmu *evsel_pmu, *ibs_fetch_pmu, *ibs_op_pmu;
static int warned_once;
/* 0: Uninitialized, 1: Yes, -1: No */
static int is_amd;
if (warned_once || is_amd == -1)
if (warned_once || !x86__is_amd_cpu())
return;
if (!is_amd) {
struct perf_env *env = evsel__env(evsel);
if (!perf_env__cpuid(env) || !env->cpuid ||
!strstarts(env->cpuid, "AuthenticAMD")) {
is_amd = -1;
return;
}
is_amd = 1;
}
evsel_pmu = evsel__find_pmu(evsel);
if (!evsel_pmu)
return;
ibs_fetch_pmu = perf_pmu__find("ibs_fetch");
ibs_op_pmu = perf_pmu__find("ibs_op");
ibs_fetch_pmu = perf_pmus__find("ibs_fetch");
ibs_op_pmu = perf_pmus__find("ibs_op");
if (ibs_fetch_pmu && ibs_fetch_pmu->type == evsel_pmu->type) {
if (attr->config & IBS_FETCH_L3MISSONLY) {

View File

@ -17,7 +17,7 @@
#include "../../../util/evlist.h"
#include "../../../util/mmap.h"
#include "../../../util/session.h"
#include "../../../util/pmu.h"
#include "../../../util/pmus.h"
#include "../../../util/debug.h"
#include "../../../util/record.h"
#include "../../../util/tsc.h"
@ -416,7 +416,7 @@ out_err:
struct auxtrace_record *intel_bts_recording_init(int *err)
{
struct perf_pmu *intel_bts_pmu = perf_pmu__find(INTEL_BTS_PMU_NAME);
struct perf_pmu *intel_bts_pmu = perf_pmus__find(INTEL_BTS_PMU_NAME);
struct intel_bts_recording *btsr;
if (!intel_bts_pmu)

View File

@ -23,7 +23,7 @@
#include "../../../util/mmap.h"
#include <subcmd/parse-options.h>
#include "../../../util/parse-events.h"
#include "../../../util/pmu.h"
#include "../../../util/pmus.h"
#include "../../../util/debug.h"
#include "../../../util/auxtrace.h"
#include "../../../util/perf_api_probe.h"
@ -1185,7 +1185,7 @@ static u64 intel_pt_reference(struct auxtrace_record *itr __maybe_unused)
struct auxtrace_record *intel_pt_recording_init(int *err)
{
struct perf_pmu *intel_pt_pmu = perf_pmu__find(INTEL_PT_PMU_NAME);
struct perf_pmu *intel_pt_pmu = perf_pmus__find(INTEL_PT_PMU_NAME);
struct intel_pt_recording *ptr;
if (!intel_pt_pmu)

View File

@ -1,9 +1,11 @@
// SPDX-License-Identifier: GPL-2.0
#include "util/pmu.h"
#include "util/pmus.h"
#include "util/env.h"
#include "map_symbol.h"
#include "mem-events.h"
#include "linux/string.h"
#include "env.h"
static char mem_loads_name[100];
static bool mem_loads_name__init;
@ -26,28 +28,12 @@ static struct perf_mem_event perf_mem_events_amd[PERF_MEM_EVENTS__MAX] = {
E("mem-ldst", "ibs_op//", "ibs_op"),
};
static int perf_mem_is_amd_cpu(void)
{
struct perf_env env = { .total_mem = 0, };
perf_env__cpuid(&env);
if (env.cpuid && strstarts(env.cpuid, "AuthenticAMD"))
return 1;
return -1;
}
struct perf_mem_event *perf_mem_events__ptr(int i)
{
/* 0: Uninitialized, 1: Yes, -1: No */
static int is_amd;
if (i >= PERF_MEM_EVENTS__MAX)
return NULL;
if (!is_amd)
is_amd = perf_mem_is_amd_cpu();
if (is_amd == 1)
if (x86__is_amd_cpu())
return &perf_mem_events_amd[i];
return &perf_mem_events_intel[i];
@ -55,13 +41,13 @@ struct perf_mem_event *perf_mem_events__ptr(int i)
bool is_mem_loads_aux_event(struct evsel *leader)
{
if (perf_pmu__find("cpu")) {
if (!pmu_have_event("cpu", "mem-loads-aux"))
return false;
} else if (perf_pmu__find("cpu_core")) {
if (!pmu_have_event("cpu_core", "mem-loads-aux"))
return false;
}
struct perf_pmu *pmu = perf_pmus__find("cpu");
if (!pmu)
pmu = perf_pmus__find("cpu_core");
if (pmu && !perf_pmu__have_event(pmu, "mem-loads-aux"))
return false;
return leader->core.attr.config == MEM_LOADS_AUX;
}
@ -82,7 +68,7 @@ char *perf_mem_events__name(int i, char *pmu_name)
pmu_name = (char *)"cpu";
}
if (pmu_have_event(pmu_name, "mem-loads-aux")) {
if (perf_pmus__have_event(pmu_name, "mem-loads-aux")) {
scnprintf(mem_loads_name, sizeof(mem_loads_name),
MEM_LOADS_AUX_NAME, pmu_name, pmu_name,
perf_mem_events__loads_ldlat);

View File

@ -10,7 +10,7 @@
#include "../../../util/debug.h"
#include "../../../util/event.h"
#include "../../../util/pmu.h"
#include "../../../util/pmu-hybrid.h"
#include "../../../util/pmus.h"
const struct sample_reg sample_reg_masks[] = {
SMPL_REG(AX, PERF_REG_X86_AX),
@ -286,20 +286,25 @@ uint64_t arch__intr_reg_mask(void)
.disabled = 1,
.exclude_kernel = 1,
};
struct perf_pmu *pmu;
int fd;
/*
* In an unnamed union, init it here to build on older gcc versions
*/
attr.sample_period = 1;
if (perf_pmu__has_hybrid()) {
if (perf_pmus__num_core_pmus() > 1) {
struct perf_pmu *pmu = NULL;
__u64 type = PERF_TYPE_RAW;
/*
* The same register set is supported among different hybrid PMUs.
* Only check the first available one.
*/
pmu = list_first_entry(&perf_pmu__hybrid_pmus, typeof(*pmu), hybrid_list);
attr.config |= (__u64)pmu->type << PERF_PMU_TYPE_SHIFT;
while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
type = pmu->type;
break;
}
attr.config |= type << PERF_PMU_TYPE_SHIFT;
}
event_attr_init(&attr);

View File

@ -14,6 +14,8 @@
#include "../../../util/intel-bts.h"
#include "../../../util/pmu.h"
#include "../../../util/fncache.h"
#include "../../../util/pmus.h"
#include "env.h"
struct pmu_alias {
char *name;
@ -168,3 +170,13 @@ char *pmu_find_alias_name(const char *name)
return __pmu_find_alias_name(name);
}
int perf_pmus__num_mem_pmus(void)
{
/* AMD uses IBS OP pmu and not a core PMU for perf mem/c2c */
if (x86__is_amd_cpu())
return 1;
/* Intel uses core pmus for perf mem/c2c */
return perf_pmus__num_core_pmus();
}

View File

@ -2,6 +2,7 @@
#include "api/fs/fs.h"
#include "util/evsel.h"
#include "util/pmu.h"
#include "util/pmus.h"
#include "util/topdown.h"
#include "topdown.h"
#include "evsel.h"
@ -22,8 +23,8 @@ bool topdown_sys_has_perf_metrics(void)
* The slots event is only available when the core PMU
* supports the perf metrics feature.
*/
pmu = perf_pmu__find_by_type(PERF_TYPE_RAW);
if (pmu && pmu_have_event(pmu->name, "slots"))
pmu = perf_pmus__find_by_type(PERF_TYPE_RAW);
if (pmu && perf_pmu__have_event(pmu, "slots"))
has_perf_metrics = true;
cached = true;

View File

@ -421,6 +421,11 @@ int bench_epoll_ctl(int argc, const char **argv)
print_summary();
close(epollfd);
perf_cpu_map__put(cpu);
for (i = 0; i < nthreads; i++)
free(worker[i].fdmap);
free(worker);
return ret;
errmem:
err(EXIT_FAILURE, "calloc");

View File

@ -549,6 +549,11 @@ int bench_epoll_wait(int argc, const char **argv)
print_summary();
close(epollfd);
perf_cpu_map__put(cpu);
for (i = 0; i < nthreads; i++)
free(worker[i].fdmap);
free(worker);
return ret;
errmem:
err(EXIT_FAILURE, "calloc");

View File

@ -118,8 +118,7 @@ static void *workerfn(void *arg)
return NULL;
}
static void create_threads(struct worker *w, pthread_attr_t thread_attr,
struct perf_cpu_map *cpu)
static void create_threads(struct worker *w, struct perf_cpu_map *cpu)
{
cpu_set_t *cpuset;
unsigned int i;
@ -133,6 +132,9 @@ static void create_threads(struct worker *w, pthread_attr_t thread_attr,
size = CPU_ALLOC_SIZE(nrcpus);
for (i = 0; i < params.nthreads; i++) {
pthread_attr_t thread_attr;
pthread_attr_init(&thread_attr);
worker[i].tid = i;
if (params.multi) {
@ -154,6 +156,7 @@ static void create_threads(struct worker *w, pthread_attr_t thread_attr,
CPU_FREE(cpuset);
err(EXIT_FAILURE, "pthread_create");
}
pthread_attr_destroy(&thread_attr);
}
CPU_FREE(cpuset);
}
@ -163,7 +166,6 @@ int bench_futex_lock_pi(int argc, const char **argv)
int ret = 0;
unsigned int i;
struct sigaction act;
pthread_attr_t thread_attr;
struct perf_cpu_map *cpu;
argc = parse_options(argc, argv, options, bench_futex_lock_pi_usage, 0);
@ -203,11 +205,9 @@ int bench_futex_lock_pi(int argc, const char **argv)
cond_init(&thread_worker);
threads_starting = params.nthreads;
pthread_attr_init(&thread_attr);
gettimeofday(&bench__start, NULL);
create_threads(worker, thread_attr, cpu);
pthread_attr_destroy(&thread_attr);
create_threads(worker, cpu);
mutex_lock(&thread_lock);
while (threads_starting)

View File

@ -121,8 +121,7 @@ static void *workerfn(void *arg __maybe_unused)
return NULL;
}
static void block_threads(pthread_t *w,
pthread_attr_t thread_attr, struct perf_cpu_map *cpu)
static void block_threads(pthread_t *w, struct perf_cpu_map *cpu)
{
cpu_set_t *cpuset;
unsigned int i;
@ -137,6 +136,9 @@ static void block_threads(pthread_t *w,
/* create and block all threads */
for (i = 0; i < params.nthreads; i++) {
pthread_attr_t thread_attr;
pthread_attr_init(&thread_attr);
CPU_ZERO_S(size, cpuset);
CPU_SET_S(perf_cpu_map__cpu(cpu, i % perf_cpu_map__nr(cpu)).cpu, size, cpuset);
@ -149,6 +151,7 @@ static void block_threads(pthread_t *w,
CPU_FREE(cpuset);
err(EXIT_FAILURE, "pthread_create");
}
pthread_attr_destroy(&thread_attr);
}
CPU_FREE(cpuset);
}
@ -165,7 +168,6 @@ int bench_futex_requeue(int argc, const char **argv)
int ret = 0;
unsigned int i, j;
struct sigaction act;
pthread_attr_t thread_attr;
struct perf_cpu_map *cpu;
argc = parse_options(argc, argv, options, bench_futex_requeue_usage, 0);
@ -209,7 +211,6 @@ int bench_futex_requeue(int argc, const char **argv)
init_stats(&requeued_stats);
init_stats(&requeuetime_stats);
pthread_attr_init(&thread_attr);
mutex_init(&thread_lock);
cond_init(&thread_parent);
cond_init(&thread_worker);
@ -219,7 +220,7 @@ int bench_futex_requeue(int argc, const char **argv)
struct timeval start, end, runtime;
/* create, launch & block all threads */
block_threads(worker, thread_attr, cpu);
block_threads(worker, cpu);
/* make sure all threads are already blocked */
mutex_lock(&thread_lock);
@ -301,7 +302,6 @@ int bench_futex_requeue(int argc, const char **argv)
cond_destroy(&thread_parent);
cond_destroy(&thread_worker);
mutex_destroy(&thread_lock);
pthread_attr_destroy(&thread_attr);
print_summary();

View File

@ -95,10 +95,12 @@ static void *waking_workerfn(void *arg)
return NULL;
}
static void wakeup_threads(struct thread_data *td, pthread_attr_t thread_attr)
static void wakeup_threads(struct thread_data *td)
{
unsigned int i;
pthread_attr_t thread_attr;
pthread_attr_init(&thread_attr);
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
pthread_barrier_init(&barrier, NULL, params.nwakes + 1);
@ -122,6 +124,7 @@ static void wakeup_threads(struct thread_data *td, pthread_attr_t thread_attr)
err(EXIT_FAILURE, "pthread_join");
pthread_barrier_destroy(&barrier);
pthread_attr_destroy(&thread_attr);
}
static void *blocked_workerfn(void *arg __maybe_unused)
@ -142,8 +145,7 @@ static void *blocked_workerfn(void *arg __maybe_unused)
return NULL;
}
static void block_threads(pthread_t *w, pthread_attr_t thread_attr,
struct perf_cpu_map *cpu)
static void block_threads(pthread_t *w, struct perf_cpu_map *cpu)
{
cpu_set_t *cpuset;
unsigned int i;
@ -158,6 +160,9 @@ static void block_threads(pthread_t *w, pthread_attr_t thread_attr,
/* create and block all threads */
for (i = 0; i < params.nthreads; i++) {
pthread_attr_t thread_attr;
pthread_attr_init(&thread_attr);
CPU_ZERO_S(size, cpuset);
CPU_SET_S(perf_cpu_map__cpu(cpu, i % perf_cpu_map__nr(cpu)).cpu, size, cpuset);
@ -170,6 +175,7 @@ static void block_threads(pthread_t *w, pthread_attr_t thread_attr,
CPU_FREE(cpuset);
err(EXIT_FAILURE, "pthread_create");
}
pthread_attr_destroy(&thread_attr);
}
CPU_FREE(cpuset);
}
@ -238,7 +244,6 @@ int bench_futex_wake_parallel(int argc, const char **argv)
int ret = 0;
unsigned int i, j;
struct sigaction act;
pthread_attr_t thread_attr;
struct thread_data *waking_worker;
struct perf_cpu_map *cpu;
@ -294,7 +299,6 @@ int bench_futex_wake_parallel(int argc, const char **argv)
init_stats(&wakeup_stats);
init_stats(&waketime_stats);
pthread_attr_init(&thread_attr);
mutex_init(&thread_lock);
cond_init(&thread_parent);
cond_init(&thread_worker);
@ -305,7 +309,7 @@ int bench_futex_wake_parallel(int argc, const char **argv)
err(EXIT_FAILURE, "calloc");
/* create, launch & block all threads */
block_threads(blocked_worker, thread_attr, cpu);
block_threads(blocked_worker, cpu);
/* make sure all threads are already blocked */
mutex_lock(&thread_lock);
@ -317,7 +321,7 @@ int bench_futex_wake_parallel(int argc, const char **argv)
usleep(100000);
/* Ok, all threads are patiently blocked, start waking folks up */
wakeup_threads(waking_worker, thread_attr);
wakeup_threads(waking_worker);
for (i = 0; i < params.nthreads; i++) {
ret = pthread_join(blocked_worker[i], NULL);
@ -336,7 +340,6 @@ int bench_futex_wake_parallel(int argc, const char **argv)
cond_destroy(&thread_parent);
cond_destroy(&thread_worker);
mutex_destroy(&thread_lock);
pthread_attr_destroy(&thread_attr);
print_summary();

View File

@ -95,8 +95,7 @@ static void print_summary(void)
rel_stddev_stats(waketime_stddev, waketime_avg));
}
static void block_threads(pthread_t *w,
pthread_attr_t thread_attr, struct perf_cpu_map *cpu)
static void block_threads(pthread_t *w, struct perf_cpu_map *cpu)
{
cpu_set_t *cpuset;
unsigned int i;
@ -110,6 +109,9 @@ static void block_threads(pthread_t *w,
/* create and block all threads */
for (i = 0; i < params.nthreads; i++) {
pthread_attr_t thread_attr;
pthread_attr_init(&thread_attr);
CPU_ZERO_S(size, cpuset);
CPU_SET_S(perf_cpu_map__cpu(cpu, i % perf_cpu_map__nr(cpu)).cpu, size, cpuset);
@ -122,6 +124,7 @@ static void block_threads(pthread_t *w,
CPU_FREE(cpuset);
err(EXIT_FAILURE, "pthread_create");
}
pthread_attr_destroy(&thread_attr);
}
CPU_FREE(cpuset);
}
@ -138,7 +141,6 @@ int bench_futex_wake(int argc, const char **argv)
int ret = 0;
unsigned int i, j;
struct sigaction act;
pthread_attr_t thread_attr;
struct perf_cpu_map *cpu;
argc = parse_options(argc, argv, options, bench_futex_wake_usage, 0);
@ -178,7 +180,6 @@ int bench_futex_wake(int argc, const char **argv)
init_stats(&wakeup_stats);
init_stats(&waketime_stats);
pthread_attr_init(&thread_attr);
mutex_init(&thread_lock);
cond_init(&thread_parent);
cond_init(&thread_worker);
@ -188,7 +189,7 @@ int bench_futex_wake(int argc, const char **argv)
struct timeval start, end, runtime;
/* create, launch & block all threads */
block_threads(worker, thread_attr, cpu);
block_threads(worker, cpu);
/* make sure all threads are already blocked */
mutex_lock(&thread_lock);
@ -228,7 +229,6 @@ int bench_futex_wake(int argc, const char **argv)
cond_destroy(&thread_parent);
cond_destroy(&thread_worker);
mutex_destroy(&thread_lock);
pthread_attr_destroy(&thread_attr);
print_summary();

View File

@ -22,6 +22,7 @@ struct pmu_scan_result {
int nr_aliases;
int nr_formats;
int nr_caps;
bool is_core;
};
static const struct option options[] = {
@ -40,13 +41,11 @@ static struct pmu_scan_result *results;
static int save_result(void)
{
struct perf_pmu *pmu;
struct perf_pmu *pmu = NULL;
struct list_head *list;
struct pmu_scan_result *r;
perf_pmu__scan(NULL);
perf_pmus__for_each_pmu(pmu) {
while ((pmu = perf_pmus__scan(pmu)) != NULL) {
r = realloc(results, (nr_pmus + 1) * sizeof(*r));
if (r == NULL)
return -ENOMEM;
@ -55,6 +54,7 @@ static int save_result(void)
r = results + nr_pmus;
r->name = strdup(pmu->name);
r->is_core = pmu->is_core;
r->nr_caps = pmu->nr_caps;
r->nr_aliases = 0;
@ -70,11 +70,11 @@ static int save_result(void)
nr_pmus++;
}
perf_pmu__destroy();
perf_pmus__destroy();
return 0;
}
static int check_result(void)
static int check_result(bool core_only)
{
struct pmu_scan_result *r;
struct perf_pmu *pmu;
@ -83,7 +83,10 @@ static int check_result(void)
for (int i = 0; i < nr_pmus; i++) {
r = &results[i];
pmu = perf_pmu__find(r->name);
if (core_only && !r->is_core)
continue;
pmu = perf_pmus__find(r->name);
if (pmu == NULL) {
pr_err("Cannot find PMU %s\n", r->name);
return -1;
@ -132,7 +135,6 @@ static int run_pmu_scan(void)
struct timeval start, end, diff;
double time_average, time_stddev;
u64 runtime_us;
unsigned int i;
int ret;
init_stats(&stats);
@ -144,26 +146,30 @@ static int run_pmu_scan(void)
return -1;
}
for (i = 0; i < iterations; i++) {
gettimeofday(&start, NULL);
perf_pmu__scan(NULL);
gettimeofday(&end, NULL);
for (int j = 0; j < 2; j++) {
bool core_only = (j == 0);
timersub(&end, &start, &diff);
runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec;
update_stats(&stats, runtime_us);
for (unsigned int i = 0; i < iterations; i++) {
gettimeofday(&start, NULL);
if (core_only)
perf_pmus__scan_core(NULL);
else
perf_pmus__scan(NULL);
gettimeofday(&end, NULL);
timersub(&end, &start, &diff);
runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec;
update_stats(&stats, runtime_us);
ret = check_result();
perf_pmu__destroy();
if (ret < 0)
break;
ret = check_result(core_only);
perf_pmus__destroy();
if (ret < 0)
break;
}
time_average = avg_stats(&stats);
time_stddev = stddev_stats(&stats);
pr_info(" Average%s PMU scanning took: %.3f usec (+- %.3f usec)\n",
core_only ? " core" : "", time_average, time_stddev);
}
time_average = avg_stats(&stats);
time_stddev = stddev_stats(&stats);
pr_info(" Average PMU scanning took: %.3f usec (+- %.3f usec)\n",
time_average, time_stddev);
delete_result();
return 0;
}

View File

@ -27,6 +27,7 @@
#include <poll.h>
#include <limits.h>
#include <err.h>
#include <linux/list.h>
#include <linux/time64.h>
#define DATASIZE 100
@ -35,8 +36,11 @@ static bool use_pipes = false;
static unsigned int nr_loops = 100;
static bool thread_mode = false;
static unsigned int num_groups = 10;
static struct list_head sender_contexts = LIST_HEAD_INIT(sender_contexts);
static struct list_head receiver_contexts = LIST_HEAD_INIT(receiver_contexts);
struct sender_context {
struct list_head list;
unsigned int num_fds;
int ready_out;
int wakefd;
@ -44,6 +48,7 @@ struct sender_context {
};
struct receiver_context {
struct list_head list;
unsigned int num_packets;
int in_fds[2];
int ready_out;
@ -170,6 +175,7 @@ static pthread_t create_worker(void *ctx, void *(*func)(void *))
if (ret != 0)
err(EXIT_FAILURE, "pthread_create failed");
pthread_attr_destroy(&attr);
return childid;
}
@ -201,6 +207,7 @@ static unsigned int group(pthread_t *pth,
if (!snd_ctx)
err(EXIT_FAILURE, "malloc()");
list_add(&snd_ctx->list, &sender_contexts);
for (i = 0; i < num_fds; i++) {
int fds[2];
struct receiver_context *ctx = malloc(sizeof(*ctx));
@ -208,6 +215,7 @@ static unsigned int group(pthread_t *pth,
if (!ctx)
err(EXIT_FAILURE, "malloc()");
list_add(&ctx->list, &receiver_contexts);
/* Create the pipe between client and server */
fdpair(fds);
@ -266,6 +274,7 @@ int bench_sched_messaging(int argc, const char **argv)
int readyfds[2], wakefds[2];
char dummy;
pthread_t *pth_tab;
struct sender_context *pos, *n;
argc = parse_options(argc, argv, options,
bench_sched_message_usage, 0);
@ -324,6 +333,13 @@ int bench_sched_messaging(int argc, const char **argv)
}
free(pth_tab);
list_for_each_entry_safe(pos, n, &sender_contexts, list) {
list_del_init(&pos->list);
free(pos);
}
list_for_each_entry_safe(pos, n, &receiver_contexts, list) {
list_del_init(&pos->list);
free(pos);
}
return 0;
}

View File

@ -184,7 +184,7 @@ out:
static int process_branch_callback(struct evsel *evsel,
struct perf_sample *sample,
struct addr_location *al __maybe_unused,
struct addr_location *al,
struct perf_annotate *ann,
struct machine *machine)
{
@ -195,21 +195,29 @@ static int process_branch_callback(struct evsel *evsel,
.hide_unresolved = symbol_conf.hide_unresolved,
.ops = &hist_iter_branch,
};
struct addr_location a;
int ret;
if (machine__resolve(machine, &a, sample) < 0)
return -1;
addr_location__init(&a);
if (machine__resolve(machine, &a, sample) < 0) {
ret = -1;
goto out;
}
if (a.sym == NULL)
return 0;
if (a.sym == NULL) {
ret = 0;
goto out;
}
if (a.map != NULL)
map__dso(a.map)->hit = 1;
hist__account_cycles(sample->branch_stack, al, sample, false, NULL);
return hist_entry_iter__add(&iter, &a, PERF_MAX_STACK_DEPTH, ann);
ret = hist_entry_iter__add(&iter, &a, PERF_MAX_STACK_DEPTH, ann);
out:
addr_location__exit(&a);
return ret;
}
static bool has_annotation(struct perf_annotate *ann)
@ -272,10 +280,12 @@ static int process_sample_event(struct perf_tool *tool,
struct addr_location al;
int ret = 0;
addr_location__init(&al);
if (machine__resolve(machine, &al, sample) < 0) {
pr_warning("problem processing %d event, skipping it.\n",
event->header.type);
return -1;
ret = -1;
goto out_put;
}
if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap))
@ -288,7 +298,7 @@ static int process_sample_event(struct perf_tool *tool,
ret = -1;
}
out_put:
addr_location__put(&al);
addr_location__exit(&al);
return ret;
}
@ -342,7 +352,7 @@ static void hists__find_annotations(struct hists *hists,
notes = symbol__annotation(he->ms.sym);
if (notes->src == NULL) {
find_next:
if (key == K_LEFT)
if (key == K_LEFT || key == '<')
nd = rb_prev(nd);
else
nd = rb_next(nd);
@ -378,9 +388,11 @@ find_next:
return;
/* fall through */
case K_RIGHT:
case '>':
next = rb_next(nd);
break;
case K_LEFT:
case '<':
next = rb_prev(nd);
break;
default:

View File

@ -21,6 +21,7 @@
#include "builtin.h"
#include "bench/bench.h"
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -260,6 +261,7 @@ int cmd_bench(int argc, const char **argv)
/* Unbuffered output */
setvbuf(stdout, NULL, _IONBF, 0);
setlocale(LC_ALL, "");
if (argc < 2) {
/* No collection specified. */

View File

@ -41,8 +41,7 @@
#include "symbol.h"
#include "ui/ui.h"
#include "ui/progress.h"
#include "pmu.h"
#include "pmu-hybrid.h"
#include "pmus.h"
#include "string2.h"
#include "util/util.h"
@ -285,25 +284,31 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
struct hist_entry *he;
struct addr_location al;
struct mem_info *mi, *mi_dup;
struct callchain_cursor *cursor;
int ret;
addr_location__init(&al);
if (machine__resolve(machine, &al, sample) < 0) {
pr_debug("problem processing %d event, skipping it.\n",
event->header.type);
return -1;
ret = -1;
goto out;
}
if (c2c.stitch_lbr)
al.thread->lbr_stitch_enable = true;
thread__set_lbr_stitch_enable(al.thread, true);
ret = sample__resolve_callchain(sample, &callchain_cursor, NULL,
cursor = get_tls_callchain_cursor();
ret = sample__resolve_callchain(sample, cursor, NULL,
evsel, &al, sysctl_perf_event_max_stack);
if (ret)
goto out;
mi = sample__resolve_mem(sample, &al);
if (mi == NULL)
return -ENOMEM;
if (mi == NULL) {
ret = -ENOMEM;
goto out;
}
/*
* The mi object is released in hists__add_entry_ops,
@ -369,7 +374,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
}
out:
addr_location__put(&al);
addr_location__exit(&al);
return ret;
free_mi:
@ -1150,14 +1155,14 @@ pid_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
{
int width = c2c_width(fmt, hpp, he->hists);
return scnprintf(hpp->buf, hpp->size, "%*d", width, he->thread->pid_);
return scnprintf(hpp->buf, hpp->size, "%*d", width, thread__pid(he->thread));
}
static int64_t
pid_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
struct hist_entry *left, struct hist_entry *right)
{
return left->thread->pid_ - right->thread->pid_;
return thread__pid(left->thread) - thread__pid(right->thread);
}
static int64_t
@ -3259,10 +3264,8 @@ static int perf_c2c__record(int argc, const char **argv)
argc = parse_options(argc, argv, options, record_mem_usage,
PARSE_OPT_KEEP_UNKNOWN);
if (!perf_pmu__has_hybrid())
rec_argc = argc + 11; /* max number of arguments */
else
rec_argc = argc + 11 * perf_pmu__hybrid_pmu_num();
/* Max number of arguments multiplied by number of PMUs that can support them. */
rec_argc = argc + 11 * perf_pmus__num_mem_pmus();
rec_argv = calloc(rec_argc + 1, sizeof(char *));
if (!rec_argv)

View File

@ -12,6 +12,7 @@
#include "util/debug.h"
#include "util/config.h"
#include <linux/string.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
@ -157,7 +158,8 @@ int cmd_config(int argc, const char **argv)
{
int i, ret = -1;
struct perf_config_set *set;
char *user_config = mkpath("%s/.perfconfig", getenv("HOME"));
char path[PATH_MAX];
char *user_config = mkpath(path, sizeof(path), "%s/.perfconfig", getenv("HOME"));
const char *config_filename;
bool changed = false;

View File

@ -90,7 +90,7 @@ struct daemon {
char *base;
struct list_head sessions;
FILE *out;
char perf[PATH_MAX];
char *perf;
int signal_fd;
time_t start;
};
@ -1490,6 +1490,14 @@ static int __cmd_ping(struct daemon *daemon, struct option parent_options[],
return send_cmd(daemon, &cmd);
}
static char *alloc_perf_exe_path(void)
{
char path[PATH_MAX];
perf_exe(path, sizeof(path));
return strdup(path);
}
int cmd_daemon(int argc, const char **argv)
{
struct option daemon_options[] = {
@ -1502,8 +1510,12 @@ int cmd_daemon(int argc, const char **argv)
"field separator", "print counts with custom separator", ","),
OPT_END()
};
int ret = -1;
__daemon.perf = alloc_perf_exe_path();
if (!__daemon.perf)
return -ENOMEM;
perf_exe(__daemon.perf, sizeof(__daemon.perf));
__daemon.out = stdout;
argc = parse_options(argc, argv, daemon_options, daemon_usage,
@ -1511,22 +1523,22 @@ int cmd_daemon(int argc, const char **argv)
if (argc) {
if (!strcmp(argv[0], "start"))
return __cmd_start(&__daemon, daemon_options, argc, argv);
ret = __cmd_start(&__daemon, daemon_options, argc, argv);
if (!strcmp(argv[0], "signal"))
return __cmd_signal(&__daemon, daemon_options, argc, argv);
ret = __cmd_signal(&__daemon, daemon_options, argc, argv);
else if (!strcmp(argv[0], "stop"))
return __cmd_stop(&__daemon, daemon_options, argc, argv);
ret = __cmd_stop(&__daemon, daemon_options, argc, argv);
else if (!strcmp(argv[0], "ping"))
return __cmd_ping(&__daemon, daemon_options, argc, argv);
pr_err("failed: unknown command '%s'\n", argv[0]);
return -1;
ret = __cmd_ping(&__daemon, daemon_options, argc, argv);
else
pr_err("failed: unknown command '%s'\n", argv[0]);
} else {
ret = setup_config(&__daemon);
if (ret)
pr_err("failed: config not found\n");
else
ret = send_cmd_list(&__daemon);
}
if (setup_config(&__daemon)) {
pr_err("failed: config not found\n");
return -1;
}
return send_cmd_list(&__daemon);
zfree(&__daemon.perf);
return ret;
}

View File

@ -409,15 +409,17 @@ static int diff__process_sample_event(struct perf_tool *tool,
return 0;
}
addr_location__init(&al);
if (machine__resolve(machine, &al, sample) < 0) {
pr_warning("problem processing %d event, skipping it.\n",
event->header.type);
return -1;
ret = -1;
goto out;
}
if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) {
ret = 0;
goto out_put;
goto out;
}
switch (compute) {
@ -426,7 +428,7 @@ static int diff__process_sample_event(struct perf_tool *tool,
NULL, NULL, NULL, sample, true)) {
pr_warning("problem incrementing symbol period, "
"skipping event\n");
goto out_put;
goto out;
}
hist__account_cycles(sample->branch_stack, &al, sample, false,
@ -437,7 +439,7 @@ static int diff__process_sample_event(struct perf_tool *tool,
if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH,
NULL)) {
pr_debug("problem adding hist entry, skipping event\n");
goto out_put;
goto out;
}
break;
@ -446,7 +448,7 @@ static int diff__process_sample_event(struct perf_tool *tool,
true)) {
pr_warning("problem incrementing symbol period, "
"skipping event\n");
goto out_put;
goto out;
}
}
@ -460,8 +462,8 @@ static int diff__process_sample_event(struct perf_tool *tool,
if (!al.filtered)
hists->stats.total_non_filtered_period += sample->period;
ret = 0;
out_put:
addr_location__put(&al);
out:
addr_location__exit(&al);
return ret;
}
@ -1376,8 +1378,8 @@ static int cycles_printf(struct hist_entry *he, struct hist_entry *pair,
end_line = map__srcline(he->ms.map, bi->sym->start + bi->end,
he->ms.sym);
if ((strncmp(start_line, SRCLINE_UNKNOWN, strlen(SRCLINE_UNKNOWN)) != 0) &&
(strncmp(end_line, SRCLINE_UNKNOWN, strlen(SRCLINE_UNKNOWN)) != 0)) {
if (start_line != SRCLINE_UNKNOWN &&
end_line != SRCLINE_UNKNOWN) {
scnprintf(buf, sizeof(buf), "[%s -> %s] %4ld",
start_line, end_line, block_he->diff.cycles);
} else {
@ -1385,8 +1387,8 @@ static int cycles_printf(struct hist_entry *he, struct hist_entry *pair,
bi->start, bi->end, block_he->diff.cycles);
}
free_srcline(start_line);
free_srcline(end_line);
zfree_srcline(&start_line);
zfree_srcline(&end_line);
return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
}

View File

@ -650,6 +650,8 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace)
break;
if (fwrite(buf, n, 1, stdout) != 1)
break;
/* flush output since stdout is in full buffering mode due to pager */
fflush(stdout);
}
}

View File

@ -19,6 +19,7 @@
#include <linux/string.h>
#include <linux/zalloc.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -389,9 +390,10 @@ static int get_html_page_path(char **page_path, const char *page)
{
struct stat st;
const char *html_path = system_path(PERF_HTML_PATH);
char path[PATH_MAX];
/* Check that we have a perf documentation directory. */
if (stat(mkpath("%s/perf.html", html_path), &st)
if (stat(mkpath(path, sizeof(path), "%s/perf.html", html_path), &st)
|| !S_ISREG(st.st_mode)) {
pr_err("'%s': not a documentation directory.", html_path);
return -1;

View File

@ -47,7 +47,7 @@
struct guest_event {
struct perf_sample sample;
union perf_event *event;
char event_buf[PERF_SAMPLE_MAX_SIZE];
char *event_buf;
};
struct guest_id {
@ -122,7 +122,7 @@ struct perf_inject {
u64 aux_id;
struct list_head samples;
struct itrace_synth_opts itrace_synth_opts;
char event_copy[PERF_SAMPLE_MAX_SIZE];
char *event_copy;
struct perf_file_section secs[HEADER_FEAT_BITS];
struct guest_session guest_session;
struct strlist *known_build_ids;
@ -320,8 +320,14 @@ perf_inject__cut_auxtrace_sample(struct perf_inject *inject,
{
size_t sz1 = sample->aux_sample.data - (void *)event;
size_t sz2 = event->header.size - sample->aux_sample.size - sz1;
union perf_event *ev = (union perf_event *)inject->event_copy;
union perf_event *ev;
if (inject->event_copy == NULL) {
inject->event_copy = malloc(PERF_SAMPLE_MAX_SIZE);
if (!inject->event_copy)
return ERR_PTR(-ENOMEM);
}
ev = (union perf_event *)inject->event_copy;
if (sz1 > event->header.size || sz2 > event->header.size ||
sz1 + sz2 > event->header.size ||
sz1 < sizeof(struct perf_event_header) + sizeof(u64))
@ -357,8 +363,11 @@ static int perf_event__repipe_sample(struct perf_tool *tool,
build_id__mark_dso_hit(tool, event, sample, evsel, machine);
if (inject->itrace_synth_opts.set && sample->aux_sample.size)
if (inject->itrace_synth_opts.set && sample->aux_sample.size) {
event = perf_inject__cut_auxtrace_sample(inject, event, sample);
if (IS_ERR(event))
return PTR_ERR(event);
}
return perf_event__repipe_synth(tool, event);
}
@ -417,7 +426,7 @@ static struct dso *findnew_dso(int pid, int tid, const char *filename,
}
vdso = is_vdso_map(filename);
nsi = nsinfo__get(thread->nsinfo);
nsi = nsinfo__get(thread__nsinfo(thread));
if (vdso) {
/* The vdso maps are always on the host and not the
@ -743,6 +752,7 @@ int perf_event__inject_buildid(struct perf_tool *tool, union perf_event *event,
struct addr_location al;
struct thread *thread;
addr_location__init(&al);
thread = machine__findnew_thread(machine, sample->pid, sample->tid);
if (thread == NULL) {
pr_err("problem processing %d event, skipping it.\n",
@ -763,6 +773,7 @@ int perf_event__inject_buildid(struct perf_tool *tool, union perf_event *event,
thread__put(thread);
repipe:
perf_event__repipe(tool, event, sample, machine);
addr_location__exit(&al);
return 0;
}
@ -1363,11 +1374,19 @@ static void guest_session__convert_time(struct guest_session *gs, u64 guest_time
static int guest_session__fetch(struct guest_session *gs)
{
void *buf = gs->ev.event_buf;
struct perf_event_header *hdr = buf;
void *buf;
struct perf_event_header *hdr;
size_t hdr_sz = sizeof(*hdr);
ssize_t ret;
buf = gs->ev.event_buf;
if (!buf) {
buf = malloc(PERF_SAMPLE_MAX_SIZE);
if (!buf)
return -ENOMEM;
gs->ev.event_buf = buf;
}
hdr = buf;
ret = readn(gs->tmp_fd, buf, hdr_sz);
if (ret < 0)
return ret;
@ -2389,5 +2408,7 @@ out_close_output:
if (!inject.in_place_update)
perf_data__close(&inject.output);
free(inject.itrace_synth_opts.vm_tm_corr_args);
free(inject.event_copy);
free(inject.guest_session.ev.event_buf);
return ret;
}

View File

@ -399,21 +399,29 @@ static u64 find_callsite(struct evsel *evsel, struct perf_sample *sample)
struct addr_location al;
struct machine *machine = &kmem_session->machines.host;
struct callchain_cursor_node *node;
struct callchain_cursor *cursor;
u64 result = sample->ip;
addr_location__init(&al);
if (alloc_func_list == NULL) {
if (build_alloc_func_list() < 0)
goto out;
}
al.thread = machine__findnew_thread(machine, sample->pid, sample->tid);
sample__resolve_callchain(sample, &callchain_cursor, NULL, evsel, &al, 16);
callchain_cursor_commit(&callchain_cursor);
cursor = get_tls_callchain_cursor();
if (cursor == NULL)
goto out;
sample__resolve_callchain(sample, cursor, NULL, evsel, &al, 16);
callchain_cursor_commit(cursor);
while (true) {
struct alloc_func key, *caller;
u64 addr;
node = callchain_cursor_current(&callchain_cursor);
node = callchain_cursor_current(cursor);
if (node == NULL)
break;
@ -427,16 +435,18 @@ static u64 find_callsite(struct evsel *evsel, struct perf_sample *sample)
else
addr = node->ip;
return addr;
result = addr;
goto out;
} else
pr_debug3("skipping alloc function: %s\n", caller->name);
callchain_cursor_advance(&callchain_cursor);
callchain_cursor_advance(cursor);
}
out:
pr_debug2("unknown callsite: %"PRIx64 "\n", sample->ip);
return sample->ip;
out:
addr_location__exit(&al);
return result;
}
struct sort_dimension {
@ -964,7 +974,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
if (perf_kmem__skip_sample(sample))
return 0;
dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid);
dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread__tid(thread));
if (evsel->handler != NULL) {
tracepoint_handler f = evsel->handler;

View File

@ -589,7 +589,7 @@ static void timehist_save_callchain(struct perf_kwork *kwork,
struct symbol *sym;
struct thread *thread;
struct callchain_cursor_node *node;
struct callchain_cursor *cursor = &callchain_cursor;
struct callchain_cursor *cursor;
if (!kwork->show_callchain || sample->callchain == NULL)
return;
@ -601,6 +601,8 @@ static void timehist_save_callchain(struct perf_kwork *kwork,
return;
}
cursor = get_tls_callchain_cursor();
if (thread__resolve_callchain(thread, cursor, evsel, sample,
NULL, NULL, kwork->max_stack + 2) != 0) {
pr_debug("Failed to resolve callchain, skipping\n");
@ -686,12 +688,18 @@ static void timehist_print_event(struct perf_kwork *kwork,
* callchain
*/
if (kwork->show_callchain) {
struct callchain_cursor *cursor = get_tls_callchain_cursor();
if (cursor == NULL)
return;
printf(" ");
sample__fprintf_sym(sample, al, 0,
EVSEL__PRINT_SYM | EVSEL__PRINT_ONELINE |
EVSEL__PRINT_CALLCHAIN_ARROW |
EVSEL__PRINT_SKIP_IGNORED,
&callchain_cursor, symbol_conf.bt_stop_list,
cursor, symbol_conf.bt_stop_list,
stdout);
}
@ -739,17 +747,22 @@ static int timehist_exit_event(struct perf_kwork *kwork,
struct kwork_atom *atom = NULL;
struct kwork_work *work = NULL;
struct addr_location al;
int ret = 0;
addr_location__init(&al);
if (machine__resolve(machine, &al, sample) < 0) {
pr_debug("Problem processing event, skipping it\n");
return -1;
ret = -1;
goto out;
}
atom = work_pop_atom(kwork, class, KWORK_TRACE_EXIT,
KWORK_TRACE_ENTRY, evsel, sample,
machine, &work);
if (work == NULL)
return -1;
if (work == NULL) {
ret = -1;
goto out;
}
if (atom != NULL) {
work->nr_atoms++;
@ -757,7 +770,9 @@ static int timehist_exit_event(struct perf_kwork *kwork,
atom_del(atom);
}
return 0;
out:
addr_location__exit(&al);
return ret;
}
static struct kwork_class kwork_irq;

View File

@ -11,10 +11,11 @@
#include "builtin.h"
#include "util/print-events.h"
#include "util/pmus.h"
#include "util/pmu.h"
#include "util/pmu-hybrid.h"
#include "util/debug.h"
#include "util/metricgroup.h"
#include "util/pfm.h"
#include "util/string2.h"
#include "util/strlist.h"
#include "util/strbuf.h"
@ -192,9 +193,14 @@ static void default_print_metric(void *ps,
if (group && print_state->metricgroups) {
if (print_state->name_only)
printf("%s ", group);
else if (print_state->metrics)
printf("\n%s:\n", group);
else
else if (print_state->metrics) {
const char *gdesc = describe_metricgroup(group);
if (gdesc)
printf("\n%s: [%s]\n", group, gdesc);
else
printf("\n%s:\n", group);
} else
printf("%s\n", group);
}
zfree(&print_state->last_metricgroups);
@ -429,7 +435,7 @@ int cmd_list(int argc, const char **argv)
.print_event = default_print_event,
.print_metric = default_print_metric,
};
const char *hybrid_name = NULL;
const char *cputype = NULL;
const char *unit_name = NULL;
bool json = false;
struct option list_options[] = {
@ -443,8 +449,8 @@ int cmd_list(int argc, const char **argv)
"Print information on the perf event names and expressions used internally by events."),
OPT_BOOLEAN(0, "deprecated", &default_ps.deprecated,
"Print deprecated events."),
OPT_STRING(0, "cputype", &hybrid_name, "hybrid cpu type",
"Limit PMU or metric printing to the given hybrid PMU (e.g. core or atom)."),
OPT_STRING(0, "cputype", &cputype, "cpu type",
"Limit PMU or metric printing to the given PMU (e.g. cpu, core or atom)."),
OPT_STRING(0, "unit", &unit_name, "PMU name",
"Limit PMU or metric printing to the specified PMU."),
OPT_INCR(0, "debug", &verbose,
@ -452,7 +458,11 @@ int cmd_list(int argc, const char **argv)
OPT_END()
};
const char * const list_usage[] = {
#ifdef HAVE_LIBPFM
"perf list [<options>] [hw|sw|cache|tracepoint|pmu|sdt|metric|metricgroup|event_glob|pfm]",
#else
"perf list [<options>] [hw|sw|cache|tracepoint|pmu|sdt|metric|metricgroup|event_glob]",
#endif
NULL
};
@ -484,10 +494,15 @@ int cmd_list(int argc, const char **argv)
assert(default_ps.visited_metrics);
if (unit_name)
default_ps.pmu_glob = strdup(unit_name);
else if (hybrid_name) {
default_ps.pmu_glob = perf_pmu__hybrid_type_to_pmu(hybrid_name);
if (!default_ps.pmu_glob)
pr_warning("WARNING: hybrid cputype is not supported!\n");
else if (cputype) {
const struct perf_pmu *pmu = perf_pmus__pmu_for_pmu_filter(cputype);
if (!pmu) {
pr_err("ERROR: cputype is not supported!\n");
ret = -1;
goto out;
}
default_ps.pmu_glob = pmu->name;
}
}
print_cb.print_start(ps);
@ -517,7 +532,7 @@ int cmd_list(int argc, const char **argv)
strcmp(argv[i], "hwcache") == 0)
print_hwcache_events(&print_cb, ps);
else if (strcmp(argv[i], "pmu") == 0)
print_pmu_events(&print_cb, ps);
perf_pmus__print_pmu_events(&print_cb, ps);
else if (strcmp(argv[i], "sdt") == 0)
print_sdt_events(&print_cb, ps);
else if (strcmp(argv[i], "metric") == 0 || strcmp(argv[i], "metrics") == 0) {
@ -529,7 +544,12 @@ int cmd_list(int argc, const char **argv)
default_ps.metricgroups = true;
default_ps.metrics = false;
metricgroup__print(&print_cb, ps);
} else if ((sep = strchr(argv[i], ':')) != NULL) {
}
#ifdef HAVE_LIBPFM
else if (strcmp(argv[i], "pfm") == 0)
print_libpfm_events(&print_cb, ps);
#endif
else if ((sep = strchr(argv[i], ':')) != NULL) {
char *old_pmu_glob = default_ps.pmu_glob;
default_ps.event_glob = strdup(argv[i]);
@ -557,7 +577,7 @@ int cmd_list(int argc, const char **argv)
event_symbols_sw, PERF_COUNT_SW_MAX);
print_tool_events(&print_cb, ps);
print_hwcache_events(&print_cb, ps);
print_pmu_events(&print_cb, ps);
perf_pmus__print_pmu_events(&print_cb, ps);
print_tracepoint_events(&print_cb, ps);
print_sdt_events(&print_cb, ps);
default_ps.metrics = true;

View File

@ -48,7 +48,7 @@ static struct target target;
#define LOCKHASH_BITS 12
#define LOCKHASH_SIZE (1UL << LOCKHASH_BITS)
static struct hlist_head lockhash_table[LOCKHASH_SIZE];
static struct hlist_head *lockhash_table;
#define __lockhashfn(key) hash_long((unsigned long)key, LOCKHASH_BITS)
#define lockhashentry(key) (lockhash_table + __lockhashfn((key)))
@ -911,7 +911,7 @@ static int lock_contention_caller(struct evsel *evsel, struct perf_sample *sampl
char *buf, int size)
{
struct thread *thread;
struct callchain_cursor *cursor = &callchain_cursor;
struct callchain_cursor *cursor;
struct machine *machine = &session->machines.host;
struct symbol *sym;
int skip = 0;
@ -925,6 +925,8 @@ static int lock_contention_caller(struct evsel *evsel, struct perf_sample *sampl
if (thread == NULL)
return -1;
cursor = get_tls_callchain_cursor();
/* use caller function name from the callchain */
ret = thread__resolve_callchain(thread, cursor, evsel, sample,
NULL, NULL, max_stack_depth);
@ -962,7 +964,7 @@ next:
static u64 callchain_id(struct evsel *evsel, struct perf_sample *sample)
{
struct callchain_cursor *cursor = &callchain_cursor;
struct callchain_cursor *cursor;
struct machine *machine = &session->machines.host;
struct thread *thread;
u64 hash = 0;
@ -973,6 +975,7 @@ static u64 callchain_id(struct evsel *evsel, struct perf_sample *sample)
if (thread == NULL)
return -1;
cursor = get_tls_callchain_cursor();
/* use caller function name from the callchain */
ret = thread__resolve_callchain(thread, cursor, evsel, sample,
NULL, NULL, max_stack_depth);
@ -1871,7 +1874,6 @@ static int __cmd_contention(int argc, const char **argv)
};
struct lock_contention con = {
.target = &target,
.result = &lockhash_table[0],
.map_nr_entries = bpf_map_entries,
.max_stack = max_stack_depth,
.stack_skip = stack_skip,
@ -1880,10 +1882,17 @@ static int __cmd_contention(int argc, const char **argv)
.owner = show_lock_owner,
};
lockhash_table = calloc(LOCKHASH_SIZE, sizeof(*lockhash_table));
if (!lockhash_table)
return -ENOMEM;
con.result = &lockhash_table[0];
session = perf_session__new(use_bpf ? NULL : &data, &eops);
if (IS_ERR(session)) {
pr_err("Initializing perf session failed\n");
return PTR_ERR(session);
err = PTR_ERR(session);
goto out_delete;
}
con.machine = &session->machines.host;
@ -1983,6 +1992,7 @@ out_delete:
evlist__delete(con.evlist);
lock_contention_finish();
perf_session__delete(session);
zfree(&lockhash_table);
return err;
}
@ -2348,6 +2358,10 @@ int cmd_lock(int argc, const char **argv)
unsigned int i;
int rc = 0;
lockhash_table = calloc(LOCKHASH_SIZE, sizeof(*lockhash_table));
if (!lockhash_table)
return -ENOMEM;
for (i = 0; i < LOCKHASH_SIZE; i++)
INIT_HLIST_HEAD(lockhash_table + i);
@ -2369,7 +2383,7 @@ int cmd_lock(int argc, const char **argv)
rc = __cmd_report(false);
} else if (!strcmp(argv[0], "script")) {
/* Aliased to 'perf script' */
return cmd_script(argc, argv);
rc = cmd_script(argc, argv);
} else if (!strcmp(argv[0], "info")) {
if (argc) {
argc = parse_options(argc, argv,
@ -2403,5 +2417,6 @@ int cmd_lock(int argc, const char **argv)
usage_with_options(lock_usage, lock_options);
}
zfree(&lockhash_table);
return rc;
}

View File

@ -17,8 +17,7 @@
#include "util/dso.h"
#include "util/map.h"
#include "util/symbol.h"
#include "util/pmu.h"
#include "util/pmu-hybrid.h"
#include "util/pmus.h"
#include "util/sample.h"
#include "util/string2.h"
#include "util/util.h"
@ -93,10 +92,8 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
argc = parse_options(argc, argv, options, record_mem_usage,
PARSE_OPT_KEEP_UNKNOWN);
if (!perf_pmu__has_hybrid())
rec_argc = argc + 9; /* max number of arguments */
else
rec_argc = argc + 9 * perf_pmu__hybrid_pmu_num();
/* Max number of arguments multiplied by number of PMUs that can support them. */
rec_argc = argc + 9 * perf_pmus__num_mem_pmus();
if (mem->cpu_list)
rec_argc += 2;
@ -202,9 +199,11 @@ dump_raw_samples(struct perf_tool *tool,
char str[PAGE_SIZE_NAME_LEN];
struct dso *dso = NULL;
addr_location__init(&al);
if (machine__resolve(machine, &al, sample) < 0) {
fprintf(stderr, "problem processing %d event, skipping it.\n",
event->header.type);
addr_location__exit(&al);
return -1;
}
@ -259,7 +258,7 @@ dump_raw_samples(struct perf_tool *tool,
dso ? dso->long_name : "???",
al.sym ? al.sym->name : "???");
out_put:
addr_location__put(&al);
addr_location__exit(&al);
return 0;
}

View File

@ -47,29 +47,29 @@ static struct {
char *target;
struct strfilter *filter;
struct nsinfo *nsi;
} params;
} *params;
/* Parse an event definition. Note that any error must die. */
static int parse_probe_event(const char *str)
{
struct perf_probe_event *pev = &params.events[params.nevents];
struct perf_probe_event *pev = &params->events[params->nevents];
int ret;
pr_debug("probe-definition(%d): %s\n", params.nevents, str);
if (++params.nevents == MAX_PROBES) {
pr_debug("probe-definition(%d): %s\n", params->nevents, str);
if (++params->nevents == MAX_PROBES) {
pr_err("Too many probes (> %d) were specified.", MAX_PROBES);
return -1;
}
pev->uprobes = params.uprobes;
if (params.target) {
pev->target = strdup(params.target);
pev->uprobes = params->uprobes;
if (params->target) {
pev->target = strdup(params->target);
if (!pev->target)
return -ENOMEM;
params.target_used = true;
params->target_used = true;
}
pev->nsi = nsinfo__get(params.nsi);
pev->nsi = nsinfo__get(params->nsi);
/* Parse a perf-probe command into event */
ret = parse_perf_probe_command(str, pev);
@ -84,12 +84,12 @@ static int params_add_filter(const char *str)
int ret = 0;
pr_debug2("Add filter: %s\n", str);
if (!params.filter) {
params.filter = strfilter__new(str, &err);
if (!params.filter)
if (!params->filter) {
params->filter = strfilter__new(str, &err);
if (!params->filter)
ret = err ? -EINVAL : -ENOMEM;
} else
ret = strfilter__or(params.filter, str, &err);
ret = strfilter__or(params->filter, str, &err);
if (ret == -EINVAL) {
pr_err("Filter parse error at %td.\n", err - str + 1);
@ -112,17 +112,17 @@ static int set_target(const char *ptr)
* TODO: Support relative path, and $PATH, $LD_LIBRARY_PATH,
* short module name.
*/
if (!params.target && ptr && *ptr == '/') {
params.target = strdup(ptr);
if (!params.target)
if (!params->target && ptr && *ptr == '/') {
params->target = strdup(ptr);
if (!params->target)
return -ENOMEM;
params.target_used = false;
params->target_used = false;
found = 1;
buf = ptr + (strlen(ptr) - 3);
if (strcmp(buf, ".ko"))
params.uprobes = true;
params->uprobes = true;
}
@ -172,15 +172,15 @@ static int opt_set_target(const struct option *opt, const char *str,
if (str) {
if (!strcmp(opt->long_name, "exec"))
params.uprobes = true;
params->uprobes = true;
else if (!strcmp(opt->long_name, "module"))
params.uprobes = false;
params->uprobes = false;
else
return ret;
/* Expand given path to absolute path, except for modulename */
if (params.uprobes || strchr(str, '/')) {
tmp = nsinfo__realpath(str, params.nsi);
if (params->uprobes || strchr(str, '/')) {
tmp = nsinfo__realpath(str, params->nsi);
if (!tmp) {
pr_warning("Failed to get the absolute path of %s: %m\n", str);
return ret;
@ -190,9 +190,9 @@ static int opt_set_target(const struct option *opt, const char *str,
if (!tmp)
return -ENOMEM;
}
free(params.target);
params.target = tmp;
params.target_used = false;
free(params->target);
params->target = tmp;
params->target_used = false;
ret = 0;
}
@ -217,7 +217,7 @@ static int opt_set_target_ns(const struct option *opt __maybe_unused,
}
nsip = nsinfo__new(ns_pid);
if (nsip && nsinfo__need_setns(nsip))
params.nsi = nsinfo__get(nsip);
params->nsi = nsinfo__get(nsip);
nsinfo__put(nsip);
ret = 0;
@ -238,14 +238,14 @@ static int opt_show_lines(const struct option *opt,
if (!str)
return 0;
if (params.command == 'L') {
if (params->command == 'L') {
pr_warning("Warning: more than one --line options are"
" detected. Only the first one is valid.\n");
return 0;
}
params.command = opt->short_name;
ret = parse_line_range_desc(str, &params.line_range);
params->command = opt->short_name;
ret = parse_line_range_desc(str, &params->line_range);
return ret;
}
@ -253,7 +253,7 @@ static int opt_show_lines(const struct option *opt,
static int opt_show_vars(const struct option *opt,
const char *str, int unset __maybe_unused)
{
struct perf_probe_event *pev = &params.events[params.nevents];
struct perf_probe_event *pev = &params->events[params->nevents];
int ret;
if (!str)
@ -264,7 +264,7 @@ static int opt_show_vars(const struct option *opt,
pr_err(" Error: '--vars' doesn't accept arguments.\n");
return -EINVAL;
}
params.command = opt->short_name;
params->command = opt->short_name;
return ret;
}
@ -276,7 +276,7 @@ static int opt_add_probe_event(const struct option *opt,
const char *str, int unset __maybe_unused)
{
if (str) {
params.command = opt->short_name;
params->command = opt->short_name;
return parse_probe_event(str);
}
@ -287,7 +287,7 @@ static int opt_set_filter_with_command(const struct option *opt,
const char *str, int unset)
{
if (!unset)
params.command = opt->short_name;
params->command = opt->short_name;
if (str)
return params_add_filter(str);
@ -306,20 +306,29 @@ static int opt_set_filter(const struct option *opt __maybe_unused,
static int init_params(void)
{
return line_range__init(&params.line_range);
int ret;
params = calloc(1, sizeof(*params));
if (!params)
return -ENOMEM;
ret = line_range__init(&params->line_range);
if (ret)
zfree(&params);
return ret;
}
static void cleanup_params(void)
{
int i;
for (i = 0; i < params.nevents; i++)
clear_perf_probe_event(params.events + i);
line_range__clear(&params.line_range);
free(params.target);
strfilter__delete(params.filter);
nsinfo__put(params.nsi);
memset(&params, 0, sizeof(params));
for (i = 0; i < params->nevents; i++)
clear_perf_probe_event(params->events + i);
line_range__clear(&params->line_range);
free(params->target);
strfilter__delete(params->filter);
nsinfo__put(params->nsi);
zfree(&params);
}
static void pr_err_with_code(const char *msg, int err)
@ -346,7 +355,7 @@ static int perf_add_probe_events(struct perf_probe_event *pevs, int npevs)
if (ret < 0)
goto out_cleanup;
if (params.command == 'D') { /* it shows definition */
if (params->command == 'D') { /* it shows definition */
if (probe_conf.bootconfig)
ret = show_bootconfig_events(pevs, npevs);
else
@ -635,7 +644,7 @@ __cmd_probe(int argc, const char **argv)
usage_with_options_msg(probe_usage, options,
"'-' is not supported.\n");
}
if (params.command && params.command != 'a') {
if (params->command && params->command != 'a') {
usage_with_options_msg(probe_usage, options,
"another command except --add is set.\n");
}
@ -644,7 +653,7 @@ __cmd_probe(int argc, const char **argv)
pr_err_with_code(" Error: Command Parse Error.", ret);
return ret;
}
params.command = 'a';
params->command = 'a';
}
ret = symbol__validate_sym_arguments();
@ -664,54 +673,54 @@ __cmd_probe(int argc, const char **argv)
* nor change running kernel. So if user gives offline vmlinux,
* ignore its buildid.
*/
if (!strchr("lda", params.command) && symbol_conf.vmlinux_name)
if (!strchr("lda", params->command) && symbol_conf.vmlinux_name)
symbol_conf.ignore_vmlinux_buildid = true;
switch (params.command) {
switch (params->command) {
case 'l':
if (params.uprobes) {
if (params->uprobes) {
pr_err(" Error: Don't use --list with --exec.\n");
parse_options_usage(probe_usage, options, "l", true);
parse_options_usage(NULL, options, "x", true);
return -EINVAL;
}
ret = show_perf_probe_events(params.filter);
ret = show_perf_probe_events(params->filter);
if (ret < 0)
pr_err_with_code(" Error: Failed to show event list.", ret);
return ret;
case 'F':
ret = show_available_funcs(params.target, params.nsi,
params.filter, params.uprobes);
ret = show_available_funcs(params->target, params->nsi,
params->filter, params->uprobes);
if (ret < 0)
pr_err_with_code(" Error: Failed to show functions.", ret);
return ret;
#ifdef HAVE_DWARF_SUPPORT
case 'L':
ret = show_line_range(&params.line_range, params.target,
params.nsi, params.uprobes);
ret = show_line_range(&params->line_range, params->target,
params->nsi, params->uprobes);
if (ret < 0)
pr_err_with_code(" Error: Failed to show lines.", ret);
return ret;
case 'V':
if (!params.filter)
params.filter = strfilter__new(DEFAULT_VAR_FILTER,
if (!params->filter)
params->filter = strfilter__new(DEFAULT_VAR_FILTER,
NULL);
ret = show_available_vars(params.events, params.nevents,
params.filter);
ret = show_available_vars(params->events, params->nevents,
params->filter);
if (ret < 0)
pr_err_with_code(" Error: Failed to show vars.", ret);
return ret;
#endif
case 'd':
ret = perf_del_probe_events(params.filter);
ret = perf_del_probe_events(params->filter);
if (ret < 0) {
pr_err_with_code(" Error: Failed to delete events.", ret);
return ret;
}
break;
case 'D':
if (probe_conf.bootconfig && params.uprobes) {
if (probe_conf.bootconfig && params->uprobes) {
pr_err(" Error: --bootconfig doesn't support uprobes.\n");
return -EINVAL;
}
@ -719,25 +728,25 @@ __cmd_probe(int argc, const char **argv)
case 'a':
/* Ensure the last given target is used */
if (params.target && !params.target_used) {
if (params->target && !params->target_used) {
pr_err(" Error: -x/-m must follow the probe definitions.\n");
parse_options_usage(probe_usage, options, "m", true);
parse_options_usage(NULL, options, "x", true);
return -EINVAL;
}
ret = perf_add_probe_events(params.events, params.nevents);
ret = perf_add_probe_events(params->events, params->nevents);
if (ret < 0) {
/*
* When perf_add_probe_events() fails it calls
* cleanup_perf_probe_events(pevs, npevs), i.e.
* cleanup_perf_probe_events(params.events, params.nevents), which
* cleanup_perf_probe_events(params->events, params->nevents), which
* will call clear_perf_probe_event(), so set nevents to zero
* to avoid cleanup_params() to call clear_perf_probe_event() again
* on the same pevs.
*/
params.nevents = 0;
params->nevents = 0;
pr_err_with_code(" Error: Failed to add events.", ret);
return ret;
}

View File

@ -48,9 +48,9 @@
#include "util/bpf-event.h"
#include "util/util.h"
#include "util/pfm.h"
#include "util/pmu.h"
#include "util/pmus.h"
#include "util/clockid.h"
#include "util/pmu-hybrid.h"
#include "util/evlist-hybrid.h"
#include "util/off_cpu.h"
#include "util/bpf-filter.h"
#include "asm/bug.h"
@ -1294,7 +1294,7 @@ static int record__open(struct record *rec)
* of waiting or event synthesis.
*/
if (opts->target.initial_delay || target__has_cpu(&opts->target) ||
perf_pmu__has_hybrid()) {
perf_pmus__num_core_pmus() > 1) {
pos = evlist__get_tracking_event(evlist);
if (!evsel__is_dummy_event(pos)) {
/* Set up dummy event. */
@ -2193,7 +2193,7 @@ static void record__uniquify_name(struct record *rec)
char *new_name;
int ret;
if (!perf_pmu__has_hybrid())
if (perf_pmus__num_core_pmus() == 1)
return;
evlist__for_each_entry(evlist, pos) {
@ -3335,6 +3335,14 @@ const char record_callchain_help[] = CALLCHAIN_RECORD_HELP
static bool dry_run;
static struct parse_events_option_args parse_events_option_args = {
.evlistp = &record.evlist,
};
static struct parse_events_option_args switch_output_parse_events_option_args = {
.evlistp = &record.sb_evlist,
};
/*
* XXX Will stay a global variable till we fix builtin-script.c to stop messing
* with it and switch to use the library functions in perf_evlist that came
@ -3343,7 +3351,7 @@ static bool dry_run;
* using pipes, etc.
*/
static struct option __record_options[] = {
OPT_CALLBACK('e', "event", &record.evlist, "event",
OPT_CALLBACK('e', "event", &parse_events_option_args, "event",
"event selector. use 'perf list' to list available events",
parse_events_option),
OPT_CALLBACK(0, "filter", &record.evlist, "filter",
@ -3496,7 +3504,8 @@ static struct option __record_options[] = {
&record.switch_output.set, "signal or size[BKMG] or time[smhd]",
"Switch output when receiving SIGUSR2 (signal) or cross a size or time threshold",
"signal"),
OPT_CALLBACK_SET(0, "switch-output-event", &record.sb_evlist, &record.switch_output_event_set, "switch output event",
OPT_CALLBACK_SET(0, "switch-output-event", &switch_output_parse_events_option_args,
&record.switch_output_event_set, "switch output event",
"switch output event selector. use 'perf list' to list available events",
parse_events_option_new_evlist),
OPT_INTEGER(0, "switch-max-files", &record.switch_output.num_files,
@ -4152,18 +4161,11 @@ int cmd_record(int argc, const char **argv)
record.opts.tail_synthesize = true;
if (rec->evlist->core.nr_entries == 0) {
if (perf_pmu__has_hybrid()) {
err = evlist__add_default_hybrid(rec->evlist,
!record.opts.no_samples);
} else {
err = __evlist__add_default(rec->evlist,
!record.opts.no_samples);
}
bool can_profile_kernel = perf_event_paranoid_check(1);
if (err < 0) {
pr_err("Not enough memory for event selector list\n");
err = parse_event(rec->evlist, can_profile_kernel ? "cycles:P" : "cycles:Pu");
if (err)
goto out;
}
}
if (rec->opts.target.tid && !rec->opts.no_inherit_set)
@ -4189,13 +4191,7 @@ int cmd_record(int argc, const char **argv)
/* Enable ignoring missing threads when -u/-p option is defined. */
rec->opts.ignore_missing_thread = rec->opts.target.uid != UINT_MAX || rec->opts.target.pid;
if (evlist__fix_hybrid_cpus(rec->evlist, rec->opts.target.cpu_list)) {
pr_err("failed to use cpu list %s\n",
rec->opts.target.cpu_list);
goto out;
}
rec->opts.target.hybrid = perf_pmu__has_hybrid();
evlist__warn_user_requested_cpus(rec->evlist, rec->opts.target.cpu_list);
if (callchain_param.enabled && callchain_param.record_mode == CALLCHAIN_FP)
arch__add_leaf_frame_record_opts(&rec->opts);

View File

@ -285,14 +285,16 @@ static int process_sample_event(struct perf_tool *tool,
if (evswitch__discard(&rep->evswitch, evsel))
return 0;
addr_location__init(&al);
if (machine__resolve(machine, &al, sample) < 0) {
pr_debug("problem processing %d event, skipping it.\n",
event->header.type);
return -1;
ret = -1;
goto out_put;
}
if (rep->stitch_lbr)
al.thread->lbr_stitch_enable = true;
thread__set_lbr_stitch_enable(al.thread, true);
if (symbol_conf.hide_unresolved && al.sym == NULL)
goto out_put;
@ -331,7 +333,7 @@ static int process_sample_event(struct perf_tool *tool,
if (ret < 0)
pr_debug("problem adding hist entry, skipping event\n");
out_put:
addr_location__put(&al);
addr_location__exit(&al);
return ret;
}
@ -829,14 +831,15 @@ static struct task *tasks_list(struct task *task, struct machine *machine)
return NULL;
/* Last one in the chain. */
if (thread->ppid == -1)
if (thread__ppid(thread) == -1)
return task;
parent_thread = machine__find_thread(machine, -1, thread->ppid);
parent_thread = machine__find_thread(machine, -1, thread__ppid(thread));
if (!parent_thread)
return ERR_PTR(-ENOENT);
parent_task = thread__priv(parent_thread);
thread__put(parent_thread);
list_add_tail(&task->list, &parent_task->children);
return tasks_list(parent_task, machine);
}
@ -869,12 +872,12 @@ static void task__print_level(struct task *task, FILE *fp, int level)
struct thread *thread = task->thread;
struct task *child;
int comm_indent = fprintf(fp, " %8d %8d %8d |%*s",
thread->pid_, thread->tid, thread->ppid,
level, "");
thread__pid(thread), thread__tid(thread),
thread__ppid(thread), level, "");
fprintf(fp, "%s\n", thread__comm_str(thread));
maps__fprintf_task(thread->maps, comm_indent, fp);
maps__fprintf_task(thread__maps(thread), comm_indent, fp);
if (!list_empty(&task->children)) {
list_for_each_entry(child, &task->children, list)
@ -911,7 +914,7 @@ static int tasks_print(struct report *rep, FILE *fp)
nd = rb_next(nd)) {
task = tasks + itask++;
task->thread = rb_entry(nd, struct thread, rb_node);
task->thread = rb_entry(nd, struct thread_rb_node, rb_node)->thread;
INIT_LIST_HEAD(&task->children);
INIT_LIST_HEAD(&task->list);
thread__set_priv(task->thread, task);

View File

@ -193,8 +193,8 @@ struct perf_sched {
* weird events, such as a task being switched away that is not current.
*/
struct perf_cpu max_cpu;
u32 curr_pid[MAX_CPUS];
struct thread *curr_thread[MAX_CPUS];
u32 *curr_pid;
struct thread **curr_thread;
char next_shortname1;
char next_shortname2;
unsigned int replay_repeat;
@ -224,7 +224,7 @@ struct perf_sched {
u64 run_avg;
u64 all_runtime;
u64 all_count;
u64 cpu_last_switched[MAX_CPUS];
u64 *cpu_last_switched;
struct rb_root_cached atom_root, sorted_atom_root, merged_atom_root;
struct list_head sort_list, cmp_pid;
bool force;
@ -916,12 +916,12 @@ static int replay_fork_event(struct perf_sched *sched,
if (verbose > 0) {
printf("fork event\n");
printf("... parent: %s/%d\n", thread__comm_str(parent), parent->tid);
printf("... child: %s/%d\n", thread__comm_str(child), child->tid);
printf("... parent: %s/%d\n", thread__comm_str(parent), thread__tid(parent));
printf("... child: %s/%d\n", thread__comm_str(child), thread__tid(child));
}
register_pid(sched, parent->tid, thread__comm_str(parent));
register_pid(sched, child->tid, thread__comm_str(child));
register_pid(sched, thread__tid(parent), thread__comm_str(parent));
register_pid(sched, thread__tid(child), thread__comm_str(child));
out_put:
thread__put(child);
thread__put(parent);
@ -1316,7 +1316,7 @@ static int latency_migrate_task_event(struct perf_sched *sched,
if (!atoms) {
if (thread_atoms_insert(sched, migrant))
goto out_put;
register_pid(sched, migrant->tid, thread__comm_str(migrant));
register_pid(sched, thread__tid(migrant), thread__comm_str(migrant));
atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
if (!atoms) {
pr_err("migration-event: Internal tree error");
@ -1359,10 +1359,13 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
sched->all_runtime += work_list->total_runtime;
sched->all_count += work_list->nb_atoms;
if (work_list->num_merged > 1)
ret = printf(" %s:(%d) ", thread__comm_str(work_list->thread), work_list->num_merged);
else
ret = printf(" %s:%d ", thread__comm_str(work_list->thread), work_list->thread->tid);
if (work_list->num_merged > 1) {
ret = printf(" %s:(%d) ", thread__comm_str(work_list->thread),
work_list->num_merged);
} else {
ret = printf(" %s:%d ", thread__comm_str(work_list->thread),
thread__tid(work_list->thread));
}
for (i = 0; i < 24 - ret; i++)
printf(" ");
@ -1380,13 +1383,17 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
{
if (l->thread == r->thread)
pid_t l_tid, r_tid;
if (RC_CHK_ACCESS(l->thread) == RC_CHK_ACCESS(r->thread))
return 0;
if (l->thread->tid < r->thread->tid)
l_tid = thread__tid(l->thread);
r_tid = thread__tid(r->thread);
if (l_tid < r_tid)
return -1;
if (l->thread->tid > r->thread->tid)
if (l_tid > r_tid)
return 1;
return (int)(l->thread - r->thread);
return (int)(RC_CHK_ACCESS(l->thread) - RC_CHK_ACCESS(r->thread));
}
static int avg_cmp(struct work_atoms *l, struct work_atoms *r)
@ -1679,14 +1686,14 @@ static int map_switch_event(struct perf_sched *sched, struct evsel *evsel,
timestamp__scnprintf_usec(timestamp, stimestamp, sizeof(stimestamp));
color_fprintf(stdout, color, " %12s secs ", stimestamp);
if (new_shortname || tr->comm_changed || (verbose > 0 && sched_in->tid)) {
if (new_shortname || tr->comm_changed || (verbose > 0 && thread__tid(sched_in))) {
const char *pid_color = color;
if (thread__has_color(sched_in))
pid_color = COLOR_PIDS;
color_fprintf(stdout, pid_color, "%s => %s:%d",
tr->shortname, thread__comm_str(sched_in), sched_in->tid);
tr->shortname, thread__comm_str(sched_in), thread__tid(sched_in));
tr->comm_changed = false;
}
@ -1948,8 +1955,8 @@ static char *timehist_get_commstr(struct thread *thread)
{
static char str[32];
const char *comm = thread__comm_str(thread);
pid_t tid = thread->tid;
pid_t pid = thread->pid_;
pid_t tid = thread__tid(thread);
pid_t pid = thread__pid(thread);
int n;
if (pid == 0)
@ -2032,7 +2039,7 @@ static char task_state_char(struct thread *thread, int state)
unsigned bit = state ? ffs(state) : 0;
/* 'I' for idle */
if (thread->tid == 0)
if (thread__tid(thread) == 0)
return 'I';
return bit < sizeof(state_to_char) - 1 ? state_to_char[bit] : '?';
@ -2067,7 +2074,7 @@ static void timehist_print_sample(struct perf_sched *sched,
for (i = 0; i < max_cpus; ++i) {
/* flag idle times with 'i'; others are sched events */
if (i == sample->cpu)
c = (thread->tid == 0) ? 'i' : 's';
c = (thread__tid(thread) == 0) ? 'i' : 's';
else
c = ' ';
printf("%c", c);
@ -2094,7 +2101,7 @@ static void timehist_print_sample(struct perf_sched *sched,
if (sched->show_wakeups && !sched->show_next)
printf(" %-*s", comm_width, "");
if (thread->tid == 0)
if (thread__tid(thread) == 0)
goto out;
if (sched->show_callchain)
@ -2104,7 +2111,7 @@ static void timehist_print_sample(struct perf_sched *sched,
EVSEL__PRINT_SYM | EVSEL__PRINT_ONELINE |
EVSEL__PRINT_CALLCHAIN_ARROW |
EVSEL__PRINT_SKIP_IGNORED,
&callchain_cursor, symbol_conf.bt_stop_list, stdout);
get_tls_callchain_cursor(), symbol_conf.bt_stop_list, stdout);
out:
printf("\n");
@ -2189,7 +2196,7 @@ static void save_task_callchain(struct perf_sched *sched,
struct evsel *evsel,
struct machine *machine)
{
struct callchain_cursor *cursor = &callchain_cursor;
struct callchain_cursor *cursor;
struct thread *thread;
/* want main thread for process - has maps */
@ -2202,6 +2209,8 @@ static void save_task_callchain(struct perf_sched *sched,
if (!sched->show_callchain || sample->callchain == NULL)
return;
cursor = get_tls_callchain_cursor();
if (thread__resolve_callchain(thread, cursor, evsel, sample,
NULL, NULL, sched->max_stack + 2) != 0) {
if (verbose > 0)
@ -2331,10 +2340,16 @@ static void save_idle_callchain(struct perf_sched *sched,
struct idle_thread_runtime *itr,
struct perf_sample *sample)
{
struct callchain_cursor *cursor;
if (!sched->show_callchain || sample->callchain == NULL)
return;
callchain_cursor__copy(&itr->cursor, &callchain_cursor);
cursor = get_tls_callchain_cursor();
if (cursor == NULL)
return;
callchain_cursor__copy(&itr->cursor, cursor);
}
static struct thread *timehist_get_thread(struct perf_sched *sched,
@ -2577,6 +2592,7 @@ static int timehist_sched_change_event(struct perf_tool *tool,
int rc = 0;
int state = evsel__intval(evsel, sample, "prev_state");
addr_location__init(&al);
if (machine__resolve(machine, &al, sample) < 0) {
pr_err("problem processing %d event. skipping it\n",
event->header.type);
@ -2626,7 +2642,7 @@ static int timehist_sched_change_event(struct perf_tool *tool,
t = ptime->end;
}
if (!sched->idle_hist || thread->tid == 0) {
if (!sched->idle_hist || thread__tid(thread) == 0) {
if (!cpu_list || test_bit(sample->cpu, cpu_bitmap))
timehist_update_runtime_stats(tr, t, tprev);
@ -2634,7 +2650,7 @@ static int timehist_sched_change_event(struct perf_tool *tool,
struct idle_thread_runtime *itr = (void *)tr;
struct thread_runtime *last_tr;
BUG_ON(thread->tid != 0);
BUG_ON(thread__tid(thread) != 0);
if (itr->last_thread == NULL)
goto out;
@ -2685,6 +2701,7 @@ out:
evsel__save_time(evsel, sample->time, sample->cpu);
addr_location__exit(&al);
return rc;
}
@ -2719,7 +2736,7 @@ static void print_thread_runtime(struct thread *t,
float stddev;
printf("%*s %5d %9" PRIu64 " ",
comm_width, timehist_get_commstr(t), t->ppid,
comm_width, timehist_get_commstr(t), thread__ppid(t),
(u64) r->run_stats.n);
print_sched_time(r->total_run_time, 8);
@ -2739,7 +2756,7 @@ static void print_thread_waittime(struct thread *t,
struct thread_runtime *r)
{
printf("%*s %5d %9" PRIu64 " ",
comm_width, timehist_get_commstr(t), t->ppid,
comm_width, timehist_get_commstr(t), thread__ppid(t),
(u64) r->run_stats.n);
print_sched_time(r->total_run_time, 8);
@ -2760,7 +2777,7 @@ struct total_run_stats {
u64 total_run_time;
};
static int __show_thread_runtime(struct thread *t, void *priv)
static int show_thread_runtime(struct thread *t, void *priv)
{
struct total_run_stats *stats = priv;
struct thread_runtime *r;
@ -2783,22 +2800,6 @@ static int __show_thread_runtime(struct thread *t, void *priv)
return 0;
}
static int show_thread_runtime(struct thread *t, void *priv)
{
if (t->dead)
return 0;
return __show_thread_runtime(t, priv);
}
static int show_deadthread_runtime(struct thread *t, void *priv)
{
if (!t->dead)
return 0;
return __show_thread_runtime(t, priv);
}
static size_t callchain__fprintf_folded(FILE *fp, struct callchain_node *node)
{
const char *sep = " <- ";
@ -2890,11 +2891,6 @@ static void timehist_print_summary(struct perf_sched *sched,
if (!task_count)
printf("<no still running tasks>\n");
printf("\nTerminated tasks:\n");
machine__for_each_thread(m, show_deadthread_runtime, &totals);
if (task_count == totals.task_count)
printf("<no terminated tasks>\n");
/* CPU idle stats not tracked when samples were skipped */
if (sched->skipped_samples && !sched->idle_hist)
return;
@ -3599,7 +3595,22 @@ int cmd_sched(int argc, const char **argv)
mutex_init(&sched.start_work_mutex);
mutex_init(&sched.work_done_wait_mutex);
for (i = 0; i < ARRAY_SIZE(sched.curr_pid); i++)
sched.curr_thread = calloc(MAX_CPUS, sizeof(*sched.curr_thread));
if (!sched.curr_thread) {
ret = -ENOMEM;
goto out;
}
sched.cpu_last_switched = calloc(MAX_CPUS, sizeof(*sched.cpu_last_switched));
if (!sched.cpu_last_switched) {
ret = -ENOMEM;
goto out;
}
sched.curr_pid = malloc(MAX_CPUS * sizeof(*sched.curr_pid));
if (!sched.curr_pid) {
ret = -ENOMEM;
goto out;
}
for (i = 0; i < MAX_CPUS; i++)
sched.curr_pid[i] = -1;
argc = parse_options_subcommand(argc, argv, sched_options, sched_subcommands,
@ -3668,6 +3679,9 @@ int cmd_sched(int argc, const char **argv)
}
out:
free(sched.curr_pid);
free(sched.cpu_last_switched);
free(sched.curr_thread);
mutex_destroy(&sched.start_work_mutex);
mutex_destroy(&sched.work_done_wait_mutex);

View File

@ -133,6 +133,7 @@ enum perf_output_field {
PERF_OUTPUT_VCPU = 1ULL << 38,
PERF_OUTPUT_CGROUP = 1ULL << 39,
PERF_OUTPUT_RETIRE_LAT = 1ULL << 40,
PERF_OUTPUT_DSOFF = 1ULL << 41,
};
struct perf_script {
@ -174,6 +175,7 @@ struct output_option {
{.str = "ip", .field = PERF_OUTPUT_IP},
{.str = "sym", .field = PERF_OUTPUT_SYM},
{.str = "dso", .field = PERF_OUTPUT_DSO},
{.str = "dsoff", .field = PERF_OUTPUT_DSOFF},
{.str = "addr", .field = PERF_OUTPUT_ADDR},
{.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET},
{.str = "srcline", .field = PERF_OUTPUT_SRCLINE},
@ -574,6 +576,9 @@ static void set_print_ip_opts(struct perf_event_attr *attr)
if (PRINT_FIELD(DSO))
output[type].print_ip_opts |= EVSEL__PRINT_DSO;
if (PRINT_FIELD(DSOFF))
output[type].print_ip_opts |= EVSEL__PRINT_DSOFF;
if (PRINT_FIELD(SYMOFFSET))
output[type].print_ip_opts |= EVSEL__PRINT_SYMOFFSET;
@ -627,6 +632,10 @@ static int perf_session__check_output_opt(struct perf_session *session)
if (evsel == NULL)
continue;
/* 'dsoff' implys 'dso' field */
if (output[j].fields & PERF_OUTPUT_DSOFF)
output[j].fields |= PERF_OUTPUT_DSO;
set_print_ip_opts(&evsel->core.attr);
tod |= output[j].fields & PERF_OUTPUT_TOD;
}
@ -792,11 +801,11 @@ static int perf_sample__fprintf_start(struct perf_script *script,
}
if (PRINT_FIELD(PID) && PRINT_FIELD(TID))
printed += fprintf(fp, "%5d/%-5d ", sample->pid, sample->tid);
printed += fprintf(fp, "%7d/%-7d ", sample->pid, sample->tid);
else if (PRINT_FIELD(PID))
printed += fprintf(fp, "%5d ", sample->pid);
printed += fprintf(fp, "%7d ", sample->pid);
else if (PRINT_FIELD(TID))
printed += fprintf(fp, "%5d ", sample->tid);
printed += fprintf(fp, "%7d ", sample->tid);
if (PRINT_FIELD(CPU)) {
if (latency_format)
@ -910,7 +919,6 @@ static int perf_sample__fprintf_brstack(struct perf_sample *sample,
{
struct branch_stack *br = sample->branch_stack;
struct branch_entry *entries = perf_sample__branch_entries(sample);
struct addr_location alf, alt;
u64 i, from, to;
int printed = 0;
@ -921,26 +929,22 @@ static int perf_sample__fprintf_brstack(struct perf_sample *sample,
from = entries[i].from;
to = entries[i].to;
if (PRINT_FIELD(DSO)) {
memset(&alf, 0, sizeof(alf));
memset(&alt, 0, sizeof(alt));
thread__find_map_fb(thread, sample->cpumode, from, &alf);
thread__find_map_fb(thread, sample->cpumode, to, &alt);
}
printed += fprintf(fp, " 0x%"PRIx64, from);
if (PRINT_FIELD(DSO)) {
printed += fprintf(fp, "(");
printed += map__fprintf_dsoname(alf.map, fp);
printed += fprintf(fp, ")");
}
struct addr_location alf, alt;
printed += fprintf(fp, "/0x%"PRIx64, to);
if (PRINT_FIELD(DSO)) {
printed += fprintf(fp, "(");
printed += map__fprintf_dsoname(alt.map, fp);
printed += fprintf(fp, ")");
}
addr_location__init(&alf);
addr_location__init(&alt);
thread__find_map_fb(thread, sample->cpumode, from, &alf);
thread__find_map_fb(thread, sample->cpumode, to, &alt);
printed += map__fprintf_dsoname_dsoff(alf.map, PRINT_FIELD(DSOFF), alf.addr, fp);
printed += fprintf(fp, "/0x%"PRIx64, to);
printed += map__fprintf_dsoname_dsoff(alt.map, PRINT_FIELD(DSOFF), alt.addr, fp);
addr_location__exit(&alt);
addr_location__exit(&alf);
} else
printed += fprintf(fp, "/0x%"PRIx64, to);
printed += print_bstack_flags(fp, entries + i);
}
@ -954,7 +958,6 @@ static int perf_sample__fprintf_brstacksym(struct perf_sample *sample,
{
struct branch_stack *br = sample->branch_stack;
struct branch_entry *entries = perf_sample__branch_entries(sample);
struct addr_location alf, alt;
u64 i, from, to;
int printed = 0;
@ -962,9 +965,10 @@ static int perf_sample__fprintf_brstacksym(struct perf_sample *sample,
return 0;
for (i = 0; i < br->nr; i++) {
struct addr_location alf, alt;
memset(&alf, 0, sizeof(alf));
memset(&alt, 0, sizeof(alt));
addr_location__init(&alf);
addr_location__init(&alt);
from = entries[i].from;
to = entries[i].to;
@ -972,19 +976,15 @@ static int perf_sample__fprintf_brstacksym(struct perf_sample *sample,
thread__find_symbol_fb(thread, sample->cpumode, to, &alt);
printed += symbol__fprintf_symname_offs(alf.sym, &alf, fp);
if (PRINT_FIELD(DSO)) {
printed += fprintf(fp, "(");
printed += map__fprintf_dsoname(alf.map, fp);
printed += fprintf(fp, ")");
}
if (PRINT_FIELD(DSO))
printed += map__fprintf_dsoname_dsoff(alf.map, PRINT_FIELD(DSOFF), alf.addr, fp);
printed += fprintf(fp, "%c", '/');
printed += symbol__fprintf_symname_offs(alt.sym, &alt, fp);
if (PRINT_FIELD(DSO)) {
printed += fprintf(fp, "(");
printed += map__fprintf_dsoname(alt.map, fp);
printed += fprintf(fp, ")");
}
if (PRINT_FIELD(DSO))
printed += map__fprintf_dsoname_dsoff(alt.map, PRINT_FIELD(DSOFF), alt.addr, fp);
printed += print_bstack_flags(fp, entries + i);
addr_location__exit(&alt);
addr_location__exit(&alf);
}
return printed;
@ -996,7 +996,6 @@ static int perf_sample__fprintf_brstackoff(struct perf_sample *sample,
{
struct branch_stack *br = sample->branch_stack;
struct branch_entry *entries = perf_sample__branch_entries(sample);
struct addr_location alf, alt;
u64 i, from, to;
int printed = 0;
@ -1004,9 +1003,10 @@ static int perf_sample__fprintf_brstackoff(struct perf_sample *sample,
return 0;
for (i = 0; i < br->nr; i++) {
struct addr_location alf, alt;
memset(&alf, 0, sizeof(alf));
memset(&alt, 0, sizeof(alt));
addr_location__init(&alf);
addr_location__init(&alt);
from = entries[i].from;
to = entries[i].to;
@ -1019,18 +1019,14 @@ static int perf_sample__fprintf_brstackoff(struct perf_sample *sample,
to = map__dso_map_ip(alt.map, to);
printed += fprintf(fp, " 0x%"PRIx64, from);
if (PRINT_FIELD(DSO)) {
printed += fprintf(fp, "(");
printed += map__fprintf_dsoname(alf.map, fp);
printed += fprintf(fp, ")");
}
if (PRINT_FIELD(DSO))
printed += map__fprintf_dsoname_dsoff(alf.map, PRINT_FIELD(DSOFF), alf.addr, fp);
printed += fprintf(fp, "/0x%"PRIx64, to);
if (PRINT_FIELD(DSO)) {
printed += fprintf(fp, "(");
printed += map__fprintf_dsoname(alt.map, fp);
printed += fprintf(fp, ")");
}
if (PRINT_FIELD(DSO))
printed += map__fprintf_dsoname_dsoff(alt.map, PRINT_FIELD(DSOFF), alt.addr, fp);
printed += print_bstack_flags(fp, entries + i);
addr_location__exit(&alt);
addr_location__exit(&alf);
}
return printed;
@ -1045,6 +1041,7 @@ static int grab_bb(u8 *buffer, u64 start, u64 end,
struct addr_location al;
bool kernel;
struct dso *dso;
int ret = 0;
if (!start || !end)
return 0;
@ -1066,7 +1063,6 @@ static int grab_bb(u8 *buffer, u64 start, u64 end,
return -ENXIO;
}
memset(&al, 0, sizeof(al));
if (end - start > MAXBB - MAXINSN) {
if (last)
pr_debug("\tbrstack does not reach to final jump (%" PRIx64 "-%" PRIx64 ")\n", start, end);
@ -1075,13 +1071,14 @@ static int grab_bb(u8 *buffer, u64 start, u64 end,
return 0;
}
addr_location__init(&al);
if (!thread__find_map(thread, *cpumode, start, &al) || (dso = map__dso(al.map)) == NULL) {
pr_debug("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end);
return 0;
goto out;
}
if (dso->data.status == DSO_DATA_STATUS_ERROR) {
pr_debug("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end);
return 0;
goto out;
}
/* Load maps to ensure dso->is_64_bit has been updated */
@ -1095,7 +1092,10 @@ static int grab_bb(u8 *buffer, u64 start, u64 end,
if (len <= 0)
pr_debug("\tcannot fetch code for block at %" PRIx64 "-%" PRIx64 "\n",
start, end);
return len;
ret = len;
out:
addr_location__exit(&al);
return ret;
}
static int map__fprintf_srccode(struct map *map, u64 addr, FILE *fp, struct srccode_state *state)
@ -1146,14 +1146,16 @@ static int print_srccode(struct thread *thread, u8 cpumode, uint64_t addr)
struct addr_location al;
int ret = 0;
memset(&al, 0, sizeof(al));
addr_location__init(&al);
thread__find_map(thread, cpumode, addr, &al);
if (!al.map)
return 0;
goto out;
ret = map__fprintf_srccode(al.map, al.addr, stdout,
&thread->srccode_state);
thread__srccode_state(thread));
if (ret)
ret += printf("\n");
out:
addr_location__exit(&al);
return ret;
}
@ -1188,14 +1190,13 @@ static int ip__fprintf_sym(uint64_t addr, struct thread *thread,
struct perf_event_attr *attr, FILE *fp)
{
struct addr_location al;
int off, printed = 0;
memset(&al, 0, sizeof(al));
int off, printed = 0, ret = 0;
addr_location__init(&al);
thread__find_map(thread, cpumode, addr, &al);
if ((*lastsym) && al.addr >= (*lastsym)->start && al.addr < (*lastsym)->end)
return 0;
goto out;
al.cpu = cpu;
al.sym = NULL;
@ -1203,7 +1204,7 @@ static int ip__fprintf_sym(uint64_t addr, struct thread *thread,
al.sym = map__find_symbol(al.map, al.addr);
if (!al.sym)
return 0;
goto out;
if (al.addr < al.sym->end)
off = al.addr - al.sym->start;
@ -1218,7 +1219,10 @@ static int ip__fprintf_sym(uint64_t addr, struct thread *thread,
printed += fprintf(fp, "\n");
*lastsym = al.sym;
return printed;
ret = printed;
out:
addr_location__exit(&al);
return ret;
}
static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
@ -1380,6 +1384,7 @@ static int perf_sample__fprintf_addr(struct perf_sample *sample,
struct addr_location al;
int printed = fprintf(fp, "%16" PRIx64, sample->addr);
addr_location__init(&al);
if (!sample_addr_correlates_sym(attr))
goto out;
@ -1393,12 +1398,10 @@ static int perf_sample__fprintf_addr(struct perf_sample *sample,
printed += symbol__fprintf_symname(al.sym, fp);
}
if (PRINT_FIELD(DSO)) {
printed += fprintf(fp, " (");
printed += map__fprintf_dsoname(al.map, fp);
printed += fprintf(fp, ")");
}
if (PRINT_FIELD(DSO))
printed += map__fprintf_dsoname_dsoff(al.map, PRINT_FIELD(DSOFF), al.addr, fp);
out:
addr_location__exit(&al);
return printed;
}
@ -1451,7 +1454,7 @@ static int perf_sample__fprintf_callindent(struct perf_sample *sample,
* The 'return' has already been popped off the stack so the depth has
* to be adjusted to match the 'call'.
*/
if (thread->ts && sample->flags & PERF_IP_FLAG_RETURN)
if (thread__ts(thread) && sample->flags & PERF_IP_FLAG_RETURN)
depth += 1;
name = resolve_branch_sym(sample, evsel, thread, al, addr_al, &ip);
@ -1554,11 +1557,13 @@ static int perf_sample__fprintf_bts(struct perf_sample *sample,
unsigned int print_opts = output[type].print_ip_opts;
struct callchain_cursor *cursor = NULL;
if (symbol_conf.use_callchain && sample->callchain &&
thread__resolve_callchain(al->thread, &callchain_cursor, evsel,
sample, NULL, NULL, scripting_max_stack) == 0)
cursor = &callchain_cursor;
if (symbol_conf.use_callchain && sample->callchain) {
cursor = get_tls_callchain_cursor();
if (thread__resolve_callchain(al->thread, cursor, evsel,
sample, NULL, NULL,
scripting_max_stack))
cursor = NULL;
}
if (cursor == NULL) {
printed += fprintf(fp, " ");
if (print_opts & EVSEL__PRINT_SRCLINE) {
@ -1589,7 +1594,7 @@ static int perf_sample__fprintf_bts(struct perf_sample *sample,
printed += fprintf(fp, "\n");
if (PRINT_FIELD(SRCCODE)) {
int ret = map__fprintf_srccode(al->map, al->addr, stdout,
&thread->srccode_state);
thread__srccode_state(thread));
if (ret) {
printed += ret;
printed += printf("\n");
@ -2098,9 +2103,9 @@ static bool show_event(struct perf_sample *sample,
if (!symbol_conf.graph_function)
return true;
if (thread->filter) {
if (depth <= thread->filter_entry_depth) {
thread->filter = false;
if (thread__filter(thread)) {
if (depth <= thread__filter_entry_depth(thread)) {
thread__set_filter(thread, false);
return false;
}
return true;
@ -2117,8 +2122,8 @@ static bool show_event(struct perf_sample *sample,
while (*s) {
unsigned len = strcspn(s, ",");
if (nlen == len && !strncmp(name, s, len)) {
thread->filter = true;
thread->filter_entry_depth = depth;
thread__set_filter(thread, true);
thread__set_filter_entry_depth(thread, depth);
return true;
}
s += len;
@ -2198,13 +2203,15 @@ static void process_event(struct perf_script *script,
struct callchain_cursor *cursor = NULL;
if (script->stitch_lbr)
al->thread->lbr_stitch_enable = true;
if (symbol_conf.use_callchain && sample->callchain &&
thread__resolve_callchain(al->thread, &callchain_cursor, evsel,
sample, NULL, NULL, scripting_max_stack) == 0)
cursor = &callchain_cursor;
thread__set_lbr_stitch_enable(al->thread, true);
if (symbol_conf.use_callchain && sample->callchain) {
cursor = get_tls_callchain_cursor();
if (thread__resolve_callchain(al->thread, cursor, evsel,
sample, NULL, NULL,
scripting_max_stack))
cursor = NULL;
}
fputc(cursor ? '\n' : ' ', fp);
sample__fprintf_sym(sample, al, 0, output[type].print_ip_opts, cursor,
symbol_conf.bt_stop_list, fp);
@ -2253,7 +2260,7 @@ static void process_event(struct perf_script *script,
if (PRINT_FIELD(SRCCODE)) {
if (map__fprintf_srccode(al->map, al->addr, stdout,
&thread->srccode_state))
thread__srccode_state(thread)))
printf("\n");
}
@ -2350,8 +2357,8 @@ static int process_sample_event(struct perf_tool *tool,
int ret = 0;
/* Set thread to NULL to indicate addr_al and al are not initialized */
addr_al.thread = NULL;
al.thread = NULL;
addr_location__init(&al);
addr_location__init(&addr_al);
ret = dlfilter__filter_event_early(dlfilter, event, sample, evsel, machine, &al, &addr_al);
if (ret) {
@ -2417,11 +2424,14 @@ static int process_sample_event(struct perf_tool *tool,
}
out_put:
if (al.thread)
addr_location__put(&al);
addr_location__exit(&addr_al);
addr_location__exit(&al);
return ret;
}
// Used when scr->per_event_dump is not set
static struct evsel_script es_stdout;
static int process_attr(struct perf_tool *tool, union perf_event *event,
struct evlist **pevlist)
{
@ -2430,7 +2440,6 @@ static int process_attr(struct perf_tool *tool, union perf_event *event,
struct evsel *evsel, *pos;
u64 sample_type;
int err;
static struct evsel_script *es;
err = perf_event__process_attr(tool, event, pevlist);
if (err)
@ -2440,14 +2449,13 @@ static int process_attr(struct perf_tool *tool, union perf_event *event,
evsel = evlist__last(*pevlist);
if (!evsel->priv) {
if (scr->per_event_dump) {
if (scr->per_event_dump) {
evsel->priv = evsel_script__new(evsel, scr->session->data);
} else {
es = zalloc(sizeof(*es));
if (!es)
if (!evsel->priv)
return -ENOMEM;
es->fp = stdout;
evsel->priv = es;
} else { // Replicate what is done in perf_script__setup_per_event_dump()
es_stdout.fp = stdout;
evsel->priv = &es_stdout;
}
}
@ -2753,7 +2761,6 @@ out_err_fclose:
static int perf_script__setup_per_event_dump(struct perf_script *script)
{
struct evsel *evsel;
static struct evsel_script es_stdout;
if (script->per_event_dump)
return perf_script__fopen_per_event_dump(script);
@ -3311,14 +3318,21 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
int unset __maybe_unused)
{
struct dirent *script_dirent, *lang_dirent;
char scripts_path[MAXPATHLEN];
char *buf, *scripts_path, *script_path, *lang_path, *first_half;
DIR *scripts_dir, *lang_dir;
char script_path[MAXPATHLEN];
char lang_path[MAXPATHLEN];
struct script_desc *desc;
char first_half[BUFSIZ];
char *script_root;
buf = malloc(3 * MAXPATHLEN + BUFSIZ);
if (!buf) {
pr_err("malloc failed\n");
exit(-1);
}
scripts_path = buf;
script_path = buf + MAXPATHLEN;
lang_path = buf + 2 * MAXPATHLEN;
first_half = buf + 3 * MAXPATHLEN;
snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path());
scripts_dir = opendir(scripts_path);
@ -3327,6 +3341,7 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
"open(%s) failed.\n"
"Check \"PERF_EXEC_PATH\" env to set scripts dir.\n",
scripts_path);
free(buf);
exit(-1);
}
@ -3357,6 +3372,7 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
desc->half_liner ? desc->half_liner : "");
}
free(buf);
exit(0);
}
@ -3883,7 +3899,7 @@ int cmd_script(int argc, const char **argv)
"comma separated output fields prepend with 'type:'. "
"+field to add and -field to remove."
"Valid types: hw,sw,trace,raw,synth. "
"Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
"Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,dsoff"
"addr,symoff,srcline,period,iregs,uregs,brstack,"
"brstacksym,flags,data_src,weight,bpf-output,brstackinsn,"
"brstackinsnlen,brstackoff,callindent,insn,insnlen,synth,"

View File

@ -44,10 +44,10 @@
#include "util/cgroup.h"
#include <subcmd/parse-options.h>
#include "util/parse-events.h"
#include "util/pmus.h"
#include "util/pmu.h"
#include "util/event.h"
#include "util/evlist.h"
#include "util/evlist-hybrid.h"
#include "util/evsel.h"
#include "util/debug.h"
#include "util/color.h"
@ -69,7 +69,6 @@
#include "util/pfm.h"
#include "util/bpf_counter.h"
#include "util/iostat.h"
#include "util/pmu-hybrid.h"
#include "util/util.h"
#include "asm/bug.h"
@ -101,6 +100,10 @@
static void print_counters(struct timespec *ts, int argc, const char **argv);
static struct evlist *evsel_list;
static struct parse_events_option_args parse_events_option_args = {
.evlistp = &evsel_list,
};
static bool all_counters_use_bpf = true;
static struct target target = {
@ -138,6 +141,7 @@ struct perf_stat {
struct perf_cpu_map *cpus;
struct perf_thread_map *threads;
enum aggr_mode aggr_mode;
u32 aggr_level;
};
static struct perf_stat perf_stat;
@ -147,6 +151,7 @@ static volatile sig_atomic_t done = 0;
static struct perf_stat_config stat_config = {
.aggr_mode = AGGR_GLOBAL,
.aggr_level = MAX_CACHE_LVL + 1,
.scale = true,
.unit_width = 4, /* strlen("unit") */
.run_count = 1,
@ -183,9 +188,6 @@ static void evlist__check_cpu_maps(struct evlist *evlist)
{
struct evsel *evsel, *warned_leader = NULL;
if (evlist__has_hybrid(evlist))
evlist__warn_hybrid_group(evlist);
evlist__for_each_entry(evlist, evsel) {
struct evsel *leader = evsel__leader(evsel);
@ -723,6 +725,8 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
all_counters_use_bpf = false;
}
evlist__reset_aggr_stats(evsel_list);
evlist__for_each_cpu(evlist_cpu_itr, evsel_list, affinity) {
counter = evlist_cpu_itr.evsel;
@ -1085,10 +1089,11 @@ static int parse_stat_cgroups(const struct option *opt,
return parse_cgroups(opt, str, unset);
}
static int parse_hybrid_type(const struct option *opt,
static int parse_cputype(const struct option *opt,
const char *str,
int unset __maybe_unused)
{
const struct perf_pmu *pmu;
struct evlist *evlist = *(struct evlist **)opt->value;
if (!list_empty(&evlist->core.entries)) {
@ -1096,19 +1101,69 @@ static int parse_hybrid_type(const struct option *opt,
return -1;
}
evlist->hybrid_pmu_name = perf_pmu__hybrid_type_to_pmu(str);
if (!evlist->hybrid_pmu_name) {
pmu = perf_pmus__pmu_for_pmu_filter(str);
if (!pmu) {
fprintf(stderr, "--cputype %s is not supported!\n", str);
return -1;
}
parse_events_option_args.pmu_filter = pmu->name;
return 0;
}
static int parse_cache_level(const struct option *opt,
const char *str,
int unset __maybe_unused)
{
int level;
u32 *aggr_mode = (u32 *)opt->value;
u32 *aggr_level = (u32 *)opt->data;
/*
* If no string is specified, aggregate based on the topology of
* Last Level Cache (LLC). Since the LLC level can change from
* architecture to architecture, set level greater than
* MAX_CACHE_LVL which will be interpreted as LLC.
*/
if (str == NULL) {
level = MAX_CACHE_LVL + 1;
goto out;
}
/*
* The format to specify cache level is LX or lX where X is the
* cache level.
*/
if (strlen(str) != 2 || (str[0] != 'l' && str[0] != 'L')) {
pr_err("Cache level must be of form L[1-%d], or l[1-%d]\n",
MAX_CACHE_LVL,
MAX_CACHE_LVL);
return -EINVAL;
}
level = atoi(&str[1]);
if (level < 1) {
pr_err("Cache level must be of form L[1-%d], or l[1-%d]\n",
MAX_CACHE_LVL,
MAX_CACHE_LVL);
return -EINVAL;
}
if (level > MAX_CACHE_LVL) {
pr_err("perf only supports max cache level of %d.\n"
"Consider increasing MAX_CACHE_LVL\n", MAX_CACHE_LVL);
return -EINVAL;
}
out:
*aggr_mode = AGGR_CACHE;
*aggr_level = level;
return 0;
}
static struct option stat_options[] = {
OPT_BOOLEAN('T', "transaction", &transaction_run,
"hardware transaction statistics"),
OPT_CALLBACK('e', "event", &evsel_list, "event",
OPT_CALLBACK('e', "event", &parse_events_option_args, "event",
"event selector. use 'perf list' to list available events",
parse_events_option),
OPT_CALLBACK(0, "filter", &evsel_list, "filter",
@ -1182,6 +1237,9 @@ static struct option stat_options[] = {
"aggregate counts per processor socket", AGGR_SOCKET),
OPT_SET_UINT(0, "per-die", &stat_config.aggr_mode,
"aggregate counts per processor die", AGGR_DIE),
OPT_CALLBACK_OPTARG(0, "per-cache", &stat_config.aggr_mode, &stat_config.aggr_level,
"cache level", "aggregate count at this cache level (Default: LLC)",
parse_cache_level),
OPT_SET_UINT(0, "per-core", &stat_config.aggr_mode,
"aggregate counts per physical processor core", AGGR_CORE),
OPT_SET_UINT(0, "per-thread", &stat_config.aggr_mode,
@ -1226,7 +1284,7 @@ static struct option stat_options[] = {
OPT_CALLBACK(0, "cputype", &evsel_list, "hybrid cpu type",
"Only enable events on applying cpu with this type "
"for hybrid platform (e.g. core or atom)",
parse_hybrid_type),
parse_cputype),
#ifdef HAVE_LIBPFM
OPT_CALLBACK(0, "pfm-events", &evsel_list, "event",
"libpfm4 event selector. use 'perf list' to list available events",
@ -1243,8 +1301,132 @@ static struct option stat_options[] = {
OPT_END()
};
/**
* Calculate the cache instance ID from the map in
* /sys/devices/system/cpu/cpuX/cache/indexY/shared_cpu_list
* Cache instance ID is the first CPU reported in the shared_cpu_list file.
*/
static int cpu__get_cache_id_from_map(struct perf_cpu cpu, char *map)
{
int id;
struct perf_cpu_map *cpu_map = perf_cpu_map__new(map);
/*
* If the map contains no CPU, consider the current CPU to
* be the first online CPU in the cache domain else use the
* first online CPU of the cache domain as the ID.
*/
if (perf_cpu_map__empty(cpu_map))
id = cpu.cpu;
else
id = perf_cpu_map__cpu(cpu_map, 0).cpu;
/* Free the perf_cpu_map used to find the cache ID */
perf_cpu_map__put(cpu_map);
return id;
}
/**
* cpu__get_cache_id - Returns 0 if successful in populating the
* cache level and cache id. Cache level is read from
* /sys/devices/system/cpu/cpuX/cache/indexY/level where as cache instance ID
* is the first CPU reported by
* /sys/devices/system/cpu/cpuX/cache/indexY/shared_cpu_list
*/
static int cpu__get_cache_details(struct perf_cpu cpu, struct perf_cache *cache)
{
int ret = 0;
u32 cache_level = stat_config.aggr_level;
struct cpu_cache_level caches[MAX_CACHE_LVL];
u32 i = 0, caches_cnt = 0;
cache->cache_lvl = (cache_level > MAX_CACHE_LVL) ? 0 : cache_level;
cache->cache = -1;
ret = build_caches_for_cpu(cpu.cpu, caches, &caches_cnt);
if (ret) {
/*
* If caches_cnt is not 0, cpu_cache_level data
* was allocated when building the topology.
* Free the allocated data before returning.
*/
if (caches_cnt)
goto free_caches;
return ret;
}
if (!caches_cnt)
return -1;
/*
* Save the data for the highest level if no
* level was specified by the user.
*/
if (cache_level > MAX_CACHE_LVL) {
int max_level_index = 0;
for (i = 1; i < caches_cnt; ++i) {
if (caches[i].level > caches[max_level_index].level)
max_level_index = i;
}
cache->cache_lvl = caches[max_level_index].level;
cache->cache = cpu__get_cache_id_from_map(cpu, caches[max_level_index].map);
/* Reset i to 0 to free entire caches[] */
i = 0;
goto free_caches;
}
for (i = 0; i < caches_cnt; ++i) {
if (caches[i].level == cache_level) {
cache->cache_lvl = cache_level;
cache->cache = cpu__get_cache_id_from_map(cpu, caches[i].map);
}
cpu_cache_level__free(&caches[i]);
}
free_caches:
/*
* Free all the allocated cpu_cache_level data.
*/
while (i < caches_cnt)
cpu_cache_level__free(&caches[i++]);
return ret;
}
/**
* aggr_cpu_id__cache - Create an aggr_cpu_id with cache instache ID, cache
* level, die and socket populated with the cache instache ID, cache level,
* die and socket for cpu. The function signature is compatible with
* aggr_cpu_id_get_t.
*/
static struct aggr_cpu_id aggr_cpu_id__cache(struct perf_cpu cpu, void *data)
{
int ret;
struct aggr_cpu_id id;
struct perf_cache cache;
id = aggr_cpu_id__die(cpu, data);
if (aggr_cpu_id__is_empty(&id))
return id;
ret = cpu__get_cache_details(cpu, &cache);
if (ret)
return id;
id.cache_lvl = cache.cache_lvl;
id.cache = cache.cache;
return id;
}
static const char *const aggr_mode__string[] = {
[AGGR_CORE] = "core",
[AGGR_CACHE] = "cache",
[AGGR_DIE] = "die",
[AGGR_GLOBAL] = "global",
[AGGR_NODE] = "node",
@ -1266,6 +1448,12 @@ static struct aggr_cpu_id perf_stat__get_die(struct perf_stat_config *config __m
return aggr_cpu_id__die(cpu, /*data=*/NULL);
}
static struct aggr_cpu_id perf_stat__get_cache_id(struct perf_stat_config *config __maybe_unused,
struct perf_cpu cpu)
{
return aggr_cpu_id__cache(cpu, /*data=*/NULL);
}
static struct aggr_cpu_id perf_stat__get_core(struct perf_stat_config *config __maybe_unused,
struct perf_cpu cpu)
{
@ -1318,6 +1506,12 @@ static struct aggr_cpu_id perf_stat__get_die_cached(struct perf_stat_config *con
return perf_stat__get_aggr(config, perf_stat__get_die, cpu);
}
static struct aggr_cpu_id perf_stat__get_cache_id_cached(struct perf_stat_config *config,
struct perf_cpu cpu)
{
return perf_stat__get_aggr(config, perf_stat__get_cache_id, cpu);
}
static struct aggr_cpu_id perf_stat__get_core_cached(struct perf_stat_config *config,
struct perf_cpu cpu)
{
@ -1349,6 +1543,8 @@ static aggr_cpu_id_get_t aggr_mode__get_aggr(enum aggr_mode aggr_mode)
return aggr_cpu_id__socket;
case AGGR_DIE:
return aggr_cpu_id__die;
case AGGR_CACHE:
return aggr_cpu_id__cache;
case AGGR_CORE:
return aggr_cpu_id__core;
case AGGR_NODE:
@ -1372,6 +1568,8 @@ static aggr_get_id_t aggr_mode__get_id(enum aggr_mode aggr_mode)
return perf_stat__get_socket_cached;
case AGGR_DIE:
return perf_stat__get_die_cached;
case AGGR_CACHE:
return perf_stat__get_cache_id_cached;
case AGGR_CORE:
return perf_stat__get_core_cached;
case AGGR_NODE:
@ -1398,7 +1596,7 @@ static int perf_stat_init_aggr_mode(void)
stat_config.aggr_map = cpu_aggr_map__new(evsel_list->core.user_requested_cpus,
get_id, /*data=*/NULL, needs_sort);
if (!stat_config.aggr_map) {
pr_err("cannot build %s map", aggr_mode__string[stat_config.aggr_mode]);
pr_err("cannot build %s map\n", aggr_mode__string[stat_config.aggr_mode]);
return -1;
}
stat_config.aggr_get_id = aggr_mode__get_id(stat_config.aggr_mode);
@ -1484,6 +1682,60 @@ static struct aggr_cpu_id perf_env__get_die_aggr_by_cpu(struct perf_cpu cpu, voi
return id;
}
static void perf_env__get_cache_id_for_cpu(struct perf_cpu cpu, struct perf_env *env,
u32 cache_level, struct aggr_cpu_id *id)
{
int i;
int caches_cnt = env->caches_cnt;
struct cpu_cache_level *caches = env->caches;
id->cache_lvl = (cache_level > MAX_CACHE_LVL) ? 0 : cache_level;
id->cache = -1;
if (!caches_cnt)
return;
for (i = caches_cnt - 1; i > -1; --i) {
struct perf_cpu_map *cpu_map;
int map_contains_cpu;
/*
* If user has not specified a level, find the fist level with
* the cpu in the map. Since building the map is expensive, do
* this only if levels match.
*/
if (cache_level <= MAX_CACHE_LVL && caches[i].level != cache_level)
continue;
cpu_map = perf_cpu_map__new(caches[i].map);
map_contains_cpu = perf_cpu_map__idx(cpu_map, cpu);
perf_cpu_map__put(cpu_map);
if (map_contains_cpu != -1) {
id->cache_lvl = caches[i].level;
id->cache = cpu__get_cache_id_from_map(cpu, caches[i].map);
return;
}
}
}
static struct aggr_cpu_id perf_env__get_cache_aggr_by_cpu(struct perf_cpu cpu,
void *data)
{
struct perf_env *env = data;
struct aggr_cpu_id id = aggr_cpu_id__empty();
if (cpu.cpu != -1) {
u32 cache_level = (perf_stat.aggr_level) ?: stat_config.aggr_level;
id.socket = env->cpu[cpu.cpu].socket_id;
id.die = env->cpu[cpu.cpu].die_id;
perf_env__get_cache_id_for_cpu(cpu, env, cache_level, &id);
}
return id;
}
static struct aggr_cpu_id perf_env__get_core_aggr_by_cpu(struct perf_cpu cpu, void *data)
{
struct perf_env *env = data;
@ -1552,6 +1804,12 @@ static struct aggr_cpu_id perf_stat__get_die_file(struct perf_stat_config *confi
return perf_env__get_die_aggr_by_cpu(cpu, &perf_stat.session->header.env);
}
static struct aggr_cpu_id perf_stat__get_cache_file(struct perf_stat_config *config __maybe_unused,
struct perf_cpu cpu)
{
return perf_env__get_cache_aggr_by_cpu(cpu, &perf_stat.session->header.env);
}
static struct aggr_cpu_id perf_stat__get_core_file(struct perf_stat_config *config __maybe_unused,
struct perf_cpu cpu)
{
@ -1583,6 +1841,8 @@ static aggr_cpu_id_get_t aggr_mode__get_aggr_file(enum aggr_mode aggr_mode)
return perf_env__get_socket_aggr_by_cpu;
case AGGR_DIE:
return perf_env__get_die_aggr_by_cpu;
case AGGR_CACHE:
return perf_env__get_cache_aggr_by_cpu;
case AGGR_CORE:
return perf_env__get_core_aggr_by_cpu;
case AGGR_NODE:
@ -1606,6 +1866,8 @@ static aggr_get_id_t aggr_mode__get_id_file(enum aggr_mode aggr_mode)
return perf_stat__get_socket_file;
case AGGR_DIE:
return perf_stat__get_die_file;
case AGGR_CACHE:
return perf_stat__get_cache_file;
case AGGR_CORE:
return perf_stat__get_core_file;
case AGGR_NODE:
@ -1650,7 +1912,7 @@ static int perf_stat_init_aggr_mode_file(struct perf_stat *st)
stat_config.aggr_map = cpu_aggr_map__new(evsel_list->core.user_requested_cpus,
get_id, env, needs_sort);
if (!stat_config.aggr_map) {
pr_err("cannot build %s map", aggr_mode__string[stat_config.aggr_mode]);
pr_err("cannot build %s map\n", aggr_mode__string[stat_config.aggr_mode]);
return -1;
}
stat_config.aggr_get_id = aggr_mode__get_id_file(stat_config.aggr_mode);
@ -1777,6 +2039,7 @@ static int add_default_attributes(void)
};
struct perf_event_attr default_null_attrs[] = {};
const char *pmu = parse_events_option_args.pmu_filter ?: "all";
/* Set attrs if no event is selected and !null_run: */
if (stat_config.null_run)
@ -1788,11 +2051,11 @@ static int add_default_attributes(void)
* will use this approach. To determine transaction support
* on an architecture test for such a metric name.
*/
if (!metricgroup__has_metric("transaction")) {
pr_err("Missing transaction metrics");
if (!metricgroup__has_metric(pmu, "transaction")) {
pr_err("Missing transaction metrics\n");
return -1;
}
return metricgroup__parse_groups(evsel_list, "transaction",
return metricgroup__parse_groups(evsel_list, pmu, "transaction",
stat_config.metric_no_group,
stat_config.metric_no_merge,
stat_config.metric_no_threshold,
@ -1805,7 +2068,7 @@ static int add_default_attributes(void)
int smi;
if (sysfs__read_int(FREEZE_ON_SMI_PATH, &smi) < 0) {
pr_err("freeze_on_smi is not supported.");
pr_err("freeze_on_smi is not supported.\n");
return -1;
}
@ -1817,15 +2080,15 @@ static int add_default_attributes(void)
smi_reset = true;
}
if (!metricgroup__has_metric("smi")) {
pr_err("Missing smi metrics");
if (!metricgroup__has_metric(pmu, "smi")) {
pr_err("Missing smi metrics\n");
return -1;
}
if (!force_metric_only)
stat_config.metric_only = true;
return metricgroup__parse_groups(evsel_list, "smi",
return metricgroup__parse_groups(evsel_list, pmu, "smi",
stat_config.metric_no_group,
stat_config.metric_no_merge,
stat_config.metric_no_threshold,
@ -1843,7 +2106,7 @@ static int add_default_attributes(void)
if (!max_level) {
pr_err("Topdown requested but the topdown metric groups aren't present.\n"
"(See perf list the metric groups have names like TopdownL1)");
"(See perf list the metric groups have names like TopdownL1)\n");
return -1;
}
if (stat_config.topdown_level > max_level) {
@ -1858,7 +2121,8 @@ static int add_default_attributes(void)
"Please print the result regularly, e.g. -I1000\n");
}
str[8] = stat_config.topdown_level + '0';
if (metricgroup__parse_groups(evsel_list, str,
if (metricgroup__parse_groups(evsel_list,
pmu, str,
/*metric_no_group=*/false,
/*metric_no_merge=*/false,
/*metric_no_threshold=*/true,
@ -1878,11 +2142,11 @@ static int add_default_attributes(void)
if (evlist__add_default_attrs(evsel_list, default_attrs0) < 0)
return -1;
if (pmu_have_event("cpu", "stalled-cycles-frontend")) {
if (perf_pmus__have_event("cpu", "stalled-cycles-frontend")) {
if (evlist__add_default_attrs(evsel_list, frontend_attrs) < 0)
return -1;
}
if (pmu_have_event("cpu", "stalled-cycles-backend")) {
if (perf_pmus__have_event("cpu", "stalled-cycles-backend")) {
if (evlist__add_default_attrs(evsel_list, backend_attrs) < 0)
return -1;
}
@ -1892,19 +2156,14 @@ static int add_default_attributes(void)
* Add TopdownL1 metrics if they exist. To minimize
* multiplexing, don't request threshold computation.
*/
/*
* TODO: TopdownL1 is disabled on hybrid CPUs to avoid a crashes
* caused by exposing latent bugs. This is fixed properly in:
* https://lore.kernel.org/lkml/bff481ba-e60a-763f-0aa0-3ee53302c480@linux.intel.com/
*/
if (metricgroup__has_metric("TopdownL1") && !perf_pmu__has_hybrid()) {
if (metricgroup__has_metric(pmu, "Default")) {
struct evlist *metric_evlist = evlist__new();
struct evsel *metric_evsel;
if (!metric_evlist)
return -1;
if (metricgroup__parse_groups(metric_evlist, "TopdownL1",
if (metricgroup__parse_groups(metric_evlist, pmu, "Default",
/*metric_no_group=*/false,
/*metric_no_merge=*/false,
/*metric_no_threshold=*/true,
@ -1915,6 +2174,7 @@ static int add_default_attributes(void)
evlist__for_each_entry(metric_evlist, metric_evsel) {
metric_evsel->skippable = true;
metric_evsel->default_metricgroup = true;
}
evlist__splice_list_tail(evsel_list, &metric_evlist->core.entries);
evlist__delete(metric_evlist);
@ -2124,7 +2384,8 @@ static struct perf_stat perf_stat = {
.stat = perf_event__process_stat_event,
.stat_round = process_stat_round_event,
},
.aggr_mode = AGGR_UNSET,
.aggr_mode = AGGR_UNSET,
.aggr_level = 0,
};
static int __cmd_report(int argc, const char **argv)
@ -2136,6 +2397,10 @@ static int __cmd_report(int argc, const char **argv)
"aggregate counts per processor socket", AGGR_SOCKET),
OPT_SET_UINT(0, "per-die", &perf_stat.aggr_mode,
"aggregate counts per processor die", AGGR_DIE),
OPT_CALLBACK_OPTARG(0, "per-cache", &perf_stat.aggr_mode, &perf_stat.aggr_level,
"cache level",
"aggregate count at this cache level (Default: LLC)",
parse_cache_level),
OPT_SET_UINT(0, "per-core", &perf_stat.aggr_mode,
"aggregate counts per physical processor core", AGGR_CORE),
OPT_SET_UINT(0, "per-node", &perf_stat.aggr_mode,
@ -2165,6 +2430,7 @@ static int __cmd_report(int argc, const char **argv)
perf_stat.session = session;
stat_config.output = stderr;
evlist__delete(evsel_list);
evsel_list = session->evlist;
ret = perf_session__process_events(session);
@ -2428,7 +2694,9 @@ int cmd_stat(int argc, const char **argv)
* knowing the target is system-wide.
*/
if (metrics) {
metricgroup__parse_groups(evsel_list, metrics,
const char *pmu = parse_events_option_args.pmu_filter ?: "all";
metricgroup__parse_groups(evsel_list, pmu, metrics,
stat_config.metric_no_group,
stat_config.metric_no_merge,
stat_config.metric_no_threshold,
@ -2457,12 +2725,8 @@ int cmd_stat(int argc, const char **argv)
}
}
if (evlist__fix_hybrid_cpus(evsel_list, target.cpu_list)) {
pr_err("failed to use cpu list %s\n", target.cpu_list);
goto out;
}
evlist__warn_user_requested_cpus(evsel_list, target.cpu_list);
target.hybrid = perf_pmu__has_hybrid();
if (evlist__create_maps(evsel_list, &target) < 0) {
if (target__has_task(&target)) {
pr_err("Problems finding threads of monitor\n");
@ -2567,8 +2831,11 @@ int cmd_stat(int argc, const char **argv)
}
}
if (!forever && status != -1 && (!interval || stat_config.summary))
if (!forever && status != -1 && (!interval || stat_config.summary)) {
if (stat_config.run_count > 1)
evlist__copy_res_stats(&stat_config, evsel_list);
print_counters(NULL, argc, argv);
}
evlist__finalize_ctlfd(evsel_list);

View File

@ -315,10 +315,10 @@ static void pid_put_sample(struct timechart *tchart, int pid, int type,
#define MAX_CPUS 4096
static u64 cpus_cstate_start_times[MAX_CPUS];
static int cpus_cstate_state[MAX_CPUS];
static u64 cpus_pstate_start_times[MAX_CPUS];
static u64 cpus_pstate_state[MAX_CPUS];
static u64 *cpus_cstate_start_times;
static int *cpus_cstate_state;
static u64 *cpus_pstate_start_times;
static u64 *cpus_pstate_state;
static int process_comm_event(struct perf_tool *tool,
union perf_event *event,
@ -498,7 +498,6 @@ static const char *cat_backtrace(union perf_event *event,
char *p = NULL;
size_t p_len;
u8 cpumode = PERF_RECORD_MISC_USER;
struct addr_location tal;
struct ip_callchain *chain = sample->callchain;
FILE *f = open_memstream(&p, &p_len);
@ -507,6 +506,7 @@ static const char *cat_backtrace(union perf_event *event,
return NULL;
}
addr_location__init(&al);
if (!chain)
goto exit;
@ -518,6 +518,7 @@ static const char *cat_backtrace(union perf_event *event,
for (i = 0; i < chain->nr; i++) {
u64 ip;
struct addr_location tal;
if (callchain_param.order == ORDER_CALLEE)
ip = chain->ips[i];
@ -544,20 +545,22 @@ static const char *cat_backtrace(union perf_event *event,
* Discard all.
*/
zfree(&p);
goto exit_put;
goto exit;
}
continue;
}
addr_location__init(&tal);
tal.filtered = 0;
if (thread__find_symbol(al.thread, cpumode, ip, &tal))
fprintf(f, "..... %016" PRIx64 " %s\n", ip, tal.sym->name);
else
fprintf(f, "..... %016" PRIx64 "\n", ip);
addr_location__exit(&tal);
}
exit_put:
addr_location__put(&al);
exit:
addr_location__exit(&al);
fclose(f);
return p;
@ -1981,12 +1984,34 @@ int cmd_timechart(int argc, const char **argv)
"perf timechart record [<options>]",
NULL
};
int ret;
cpus_cstate_start_times = calloc(MAX_CPUS, sizeof(*cpus_cstate_start_times));
if (!cpus_cstate_start_times)
return -ENOMEM;
cpus_cstate_state = calloc(MAX_CPUS, sizeof(*cpus_cstate_state));
if (!cpus_cstate_state) {
ret = -ENOMEM;
goto out;
}
cpus_pstate_start_times = calloc(MAX_CPUS, sizeof(*cpus_pstate_start_times));
if (!cpus_pstate_start_times) {
ret = -ENOMEM;
goto out;
}
cpus_pstate_state = calloc(MAX_CPUS, sizeof(*cpus_pstate_state));
if (!cpus_pstate_state) {
ret = -ENOMEM;
goto out;
}
argc = parse_options_subcommand(argc, argv, timechart_options, timechart_subcommands,
timechart_usage, PARSE_OPT_STOP_AT_NON_OPTION);
if (tchart.power_only && tchart.tasks_only) {
pr_err("-P and -T options cannot be used at the same time.\n");
return -1;
ret = -1;
goto out;
}
if (argc && strlen(argv[0]) > 2 && strstarts("record", argv[0])) {
@ -1996,17 +2021,25 @@ int cmd_timechart(int argc, const char **argv)
if (tchart.power_only && tchart.tasks_only) {
pr_err("-P and -T options cannot be used at the same time.\n");
return -1;
ret = -1;
goto out;
}
if (tchart.io_only)
return timechart__io_record(argc, argv);
ret = timechart__io_record(argc, argv);
else
return timechart__record(&tchart, argc, argv);
ret = timechart__record(&tchart, argc, argv);
goto out;
} else if (argc)
usage_with_options(timechart_usage, timechart_options);
setup_pager();
return __cmd_timechart(&tchart, output_name);
ret = __cmd_timechart(&tchart, output_name);
out:
zfree(&cpus_cstate_start_times);
zfree(&cpus_cstate_state);
zfree(&cpus_pstate_start_times);
zfree(&cpus_pstate_state);
return ret;
}

View File

@ -137,10 +137,10 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
}
notes = symbol__annotation(sym);
mutex_lock(&notes->lock);
annotation__lock(notes);
if (!symbol__hists(sym, top->evlist->core.nr_entries)) {
mutex_unlock(&notes->lock);
annotation__unlock(notes);
pr_err("Not enough memory for annotating '%s' symbol!\n",
sym->name);
sleep(1);
@ -156,7 +156,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
pr_err("Couldn't annotate %s: %s\n", sym->name, msg);
}
mutex_unlock(&notes->lock);
annotation__unlock(notes);
return err;
}
@ -211,12 +211,12 @@ static void perf_top__record_precise_ip(struct perf_top *top,
notes = symbol__annotation(sym);
if (!mutex_trylock(&notes->lock))
if (!annotation__trylock(notes))
return;
err = hist_entry__inc_addr_samples(he, sample, evsel, ip);
mutex_unlock(&notes->lock);
annotation__unlock(notes);
if (unlikely(err)) {
/*
@ -253,7 +253,7 @@ static void perf_top__show_details(struct perf_top *top)
symbol = he->ms.sym;
notes = symbol__annotation(symbol);
mutex_lock(&notes->lock);
annotation__lock(notes);
symbol__calc_percent(symbol, evsel);
@ -274,7 +274,7 @@ static void perf_top__show_details(struct perf_top *top)
if (more != 0)
printf("%d lines not displayed, maybe increase display entries [e]\n", more);
out_unlock:
mutex_unlock(&notes->lock);
annotation__unlock(notes);
}
static void perf_top__resort_hists(struct perf_top *t)
@ -392,7 +392,7 @@ static void prompt_percent(int *target, const char *msg)
static void perf_top__prompt_symbol(struct perf_top *top, const char *msg)
{
char *buf = malloc(0), *p;
char *buf = NULL, *p;
struct hist_entry *syme = top->sym_filter_entry, *n, *found = NULL;
struct hists *hists = evsel__hists(top->sym_evsel);
struct rb_node *next;
@ -773,11 +773,12 @@ static void perf_event__process_sample(struct perf_tool *tool,
if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
top->exact_samples++;
addr_location__init(&al);
if (machine__resolve(machine, &al, sample) < 0)
return;
goto out;
if (top->stitch_lbr)
al.thread->lbr_stitch_enable = true;
thread__set_lbr_stitch_enable(al.thread, true);
if (!machine->kptr_restrict_warned &&
symbol_conf.kptr_restrict &&
@ -848,7 +849,8 @@ static void perf_event__process_sample(struct perf_tool *tool,
mutex_unlock(&hists->lock);
}
addr_location__put(&al);
out:
addr_location__exit(&al);
}
static void
@ -1225,6 +1227,14 @@ static void init_process_thread(struct perf_top *top)
cond_init(&top->qe.cond);
}
static void exit_process_thread(struct perf_top *top)
{
ordered_events__free(&top->qe.data[0]);
ordered_events__free(&top->qe.data[1]);
mutex_destroy(&top->qe.mutex);
cond_destroy(&top->qe.cond);
}
static int __cmd_top(struct perf_top *top)
{
struct record_opts *opts = &top->record_opts;
@ -1355,6 +1365,7 @@ out_join_thread:
cond_signal(&top->qe.cond);
pthread_join(thread_process, NULL);
perf_set_singlethreaded();
exit_process_thread(top);
return ret;
}
@ -1440,12 +1451,15 @@ int cmd_top(int argc, const char **argv)
.max_stack = sysctl__max_stack(),
.nr_threads_synthesize = UINT_MAX,
};
struct parse_events_option_args parse_events_option_args = {
.evlistp = &top.evlist,
};
bool branch_call_mode = false;
struct record_opts *opts = &top.record_opts;
struct target *target = &opts->target;
const char *disassembler_style = NULL, *objdump_path = NULL, *addr2line_path = NULL;
const struct option options[] = {
OPT_CALLBACK('e', "event", &top.evlist, "event",
OPT_CALLBACK('e', "event", &parse_events_option_args, "event",
"event selector. use 'perf list' to list available events",
parse_events_option),
OPT_U64('c', "count", &opts->user_interval, "event period to sample"),
@ -1650,10 +1664,12 @@ int cmd_top(int argc, const char **argv)
if (annotate_check_args(&top.annotation_opts) < 0)
goto out_delete_evlist;
if (!top.evlist->core.nr_entries &&
evlist__add_default(top.evlist) < 0) {
pr_err("Not enough memory for event selector list\n");
goto out_delete_evlist;
if (!top.evlist->core.nr_entries) {
bool can_profile_kernel = perf_event_paranoid_check(1);
int err = parse_event(top.evlist, can_profile_kernel ? "cycles:P" : "cycles:Pu");
if (err)
goto out_delete_evlist;
}
status = evswitch__init(&top.evswitch, top.evlist, stderr);

View File

@ -914,7 +914,7 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
#include "trace/beauty/socket_type.c"
#include "trace/beauty/waitid_options.c"
static struct syscall_fmt syscall_fmts[] = {
static const struct syscall_fmt syscall_fmts[] = {
{ .name = "access",
.arg = { [1] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, },
{ .name = "arch_prctl",
@ -1176,18 +1176,21 @@ static int syscall_fmt__cmp(const void *name, const void *fmtp)
return strcmp(name, fmt->name);
}
static struct syscall_fmt *__syscall_fmt__find(struct syscall_fmt *fmts, const int nmemb, const char *name)
static const struct syscall_fmt *__syscall_fmt__find(const struct syscall_fmt *fmts,
const int nmemb,
const char *name)
{
return bsearch(name, fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
}
static struct syscall_fmt *syscall_fmt__find(const char *name)
static const struct syscall_fmt *syscall_fmt__find(const char *name)
{
const int nmemb = ARRAY_SIZE(syscall_fmts);
return __syscall_fmt__find(syscall_fmts, nmemb, name);
}
static struct syscall_fmt *__syscall_fmt__find_by_alias(struct syscall_fmt *fmts, const int nmemb, const char *alias)
static const struct syscall_fmt *__syscall_fmt__find_by_alias(const struct syscall_fmt *fmts,
const int nmemb, const char *alias)
{
int i;
@ -1199,7 +1202,7 @@ static struct syscall_fmt *__syscall_fmt__find_by_alias(struct syscall_fmt *fmts
return NULL;
}
static struct syscall_fmt *syscall_fmt__find_by_alias(const char *alias)
static const struct syscall_fmt *syscall_fmt__find_by_alias(const char *alias)
{
const int nmemb = ARRAY_SIZE(syscall_fmts);
return __syscall_fmt__find_by_alias(syscall_fmts, nmemb, alias);
@ -1224,7 +1227,7 @@ struct syscall {
bool nonexistent;
struct tep_format_field *args;
const char *name;
struct syscall_fmt *fmt;
const struct syscall_fmt *fmt;
struct syscall_arg_fmt *arg_fmt;
};
@ -1383,12 +1386,13 @@ static int thread__read_fd_path(struct thread *thread, int fd)
struct stat st;
int ret;
if (thread->pid_ == thread->tid) {
if (thread__pid(thread) == thread__tid(thread)) {
scnprintf(linkname, sizeof(linkname),
"/proc/%d/fd/%d", thread->pid_, fd);
"/proc/%d/fd/%d", thread__pid(thread), fd);
} else {
scnprintf(linkname, sizeof(linkname),
"/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
"/proc/%d/task/%d/fd/%d",
thread__pid(thread), thread__tid(thread), fd);
}
if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
@ -1556,7 +1560,7 @@ static size_t trace__fprintf_comm_tid(struct trace *trace, struct thread *thread
if (trace->multiple_threads) {
if (trace->show_comm)
printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
printed += fprintf(fp, "%d ", thread->tid);
printed += fprintf(fp, "%d ", thread__tid(thread));
}
return printed;
@ -1673,7 +1677,7 @@ static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
return 0;
}
static struct syscall_arg_fmt syscall_arg_fmts__by_name[] = {
static const struct syscall_arg_fmt syscall_arg_fmts__by_name[] = {
{ .name = "msr", .scnprintf = SCA_X86_MSR, .strtoul = STUL_X86_MSR, },
{ .name = "vector", .scnprintf = SCA_X86_IRQ_VECTORS, .strtoul = STUL_X86_IRQ_VECTORS, },
};
@ -1684,13 +1688,14 @@ static int syscall_arg_fmt__cmp(const void *name, const void *fmtp)
return strcmp(name, fmt->name);
}
static struct syscall_arg_fmt *
__syscall_arg_fmt__find_by_name(struct syscall_arg_fmt *fmts, const int nmemb, const char *name)
static const struct syscall_arg_fmt *
__syscall_arg_fmt__find_by_name(const struct syscall_arg_fmt *fmts, const int nmemb,
const char *name)
{
return bsearch(name, fmts, nmemb, sizeof(struct syscall_arg_fmt), syscall_arg_fmt__cmp);
}
static struct syscall_arg_fmt *syscall_arg_fmt__find_by_name(const char *name)
static const struct syscall_arg_fmt *syscall_arg_fmt__find_by_name(const char *name)
{
const int nmemb = ARRAY_SIZE(syscall_arg_fmts__by_name);
return __syscall_arg_fmt__find_by_name(syscall_arg_fmts__by_name, nmemb, name);
@ -1735,8 +1740,9 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
* 7 unsigned long
*/
arg->scnprintf = SCA_FD;
} else {
struct syscall_arg_fmt *fmt = syscall_arg_fmt__find_by_name(field->name);
} else {
const struct syscall_arg_fmt *fmt =
syscall_arg_fmt__find_by_name(field->name);
if (fmt) {
arg->scnprintf = fmt->scnprintf;
@ -2200,7 +2206,8 @@ static void thread__update_stats(struct thread *thread, struct thread_trace *ttr
memset(new_errnos + stats->max_errno, 0, (err - stats->max_errno) * sizeof(u32));
} else {
pr_debug("Not enough memory for errno stats for thread \"%s\"(%d/%d), results will be incomplete\n",
thread__comm_str(thread), thread->pid_, thread->tid);
thread__comm_str(thread), thread__pid(thread),
thread__tid(thread));
return;
}
@ -2411,13 +2418,15 @@ static int trace__resolve_callchain(struct trace *trace, struct evsel *evsel,
int max_stack = evsel->core.attr.sample_max_stack ?
evsel->core.attr.sample_max_stack :
trace->max_stack;
int err;
int err = -1;
addr_location__init(&al);
if (machine__resolve(trace->host, &al, sample) < 0)
return -1;
goto out;
err = thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, max_stack);
addr_location__put(&al);
out:
addr_location__exit(&al);
return err;
}
@ -2428,7 +2437,7 @@ static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sam
EVSEL__PRINT_DSO |
EVSEL__PRINT_UNKNOWN_AS_ADDR;
return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, symbol_conf.bt_stop_list, trace->output);
return sample__fprintf_callchain(sample, 38, print_opts, get_tls_callchain_cursor(), symbol_conf.bt_stop_list, trace->output);
}
static const char *errno_to_name(struct evsel *evsel, int err)
@ -2482,9 +2491,11 @@ static int trace__sys_exit(struct trace *trace, struct evsel *evsel,
goto out;
if (sample->callchain) {
callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
struct callchain_cursor *cursor = get_tls_callchain_cursor();
callchain_ret = trace__resolve_callchain(trace, evsel, sample, cursor);
if (callchain_ret == 0) {
if (callchain_cursor.nr < trace->min_stack)
if (cursor->nr < trace->min_stack)
goto out;
callchain_ret = 1;
}
@ -2545,7 +2556,7 @@ errno_print: {
if (child != NULL) {
fprintf(trace->output, "%ld", ret);
if (child->comm_set)
if (thread__comm_set(child))
fprintf(trace->output, " (%s)", thread__comm_str(child));
thread__put(child);
}
@ -2786,9 +2797,11 @@ static int trace__event_handler(struct trace *trace, struct evsel *evsel,
thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
if (sample->callchain) {
callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
struct callchain_cursor *cursor = get_tls_callchain_cursor();
callchain_ret = trace__resolve_callchain(trace, evsel, sample, cursor);
if (callchain_ret == 0) {
if (callchain_cursor.nr < trace->min_stack)
if (cursor->nr < trace->min_stack)
goto out;
callchain_ret = 1;
}
@ -2886,12 +2899,15 @@ static int trace__pgfault(struct trace *trace,
int err = -1;
int callchain_ret = 0;
addr_location__init(&al);
thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
if (sample->callchain) {
callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
struct callchain_cursor *cursor = get_tls_callchain_cursor();
callchain_ret = trace__resolve_callchain(trace, evsel, sample, cursor);
if (callchain_ret == 0) {
if (callchain_cursor.nr < trace->min_stack)
if (cursor->nr < trace->min_stack)
goto out_put;
callchain_ret = 1;
}
@ -2946,6 +2962,7 @@ out:
err = 0;
out_put:
thread__put(thread);
addr_location__exit(&al);
return err;
}
@ -3611,14 +3628,16 @@ static int trace__set_filter_loop_pids(struct trace *trace)
struct thread *thread = machine__find_thread(trace->host, pids[0], pids[0]);
while (thread && nr < ARRAY_SIZE(pids)) {
struct thread *parent = machine__find_thread(trace->host, thread->ppid, thread->ppid);
struct thread *parent = machine__find_thread(trace->host,
thread__ppid(thread),
thread__ppid(thread));
if (parent == NULL)
break;
if (!strcmp(thread__comm_str(parent), "sshd") ||
strstarts(thread__comm_str(parent), "gnome-terminal")) {
pids[nr++] = parent->tid;
pids[nr++] = thread__tid(parent);
break;
}
thread = parent;
@ -4317,7 +4336,7 @@ static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trac
ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread__tid(thread));
printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
printed += fprintf(fp, "%.1f%%", ratio);
if (ttrace->pfmaj)
@ -4339,11 +4358,13 @@ static unsigned long thread__nr_events(struct thread_trace *ttrace)
return ttrace ? ttrace->nr_events : 0;
}
DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
DEFINE_RESORT_RB(threads,
(thread__nr_events(thread__priv(a->thread)) <
thread__nr_events(thread__priv(b->thread))),
struct thread *thread;
)
{
entry->thread = rb_entry(nd, struct thread, rb_node);
entry->thread = rb_entry(nd, struct thread_rb_node, rb_node)->thread;
}
static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
@ -4458,7 +4479,7 @@ static void evsel__set_syscall_arg_fmt(struct evsel *evsel, const char *name)
struct syscall_arg_fmt *fmt = evsel__syscall_arg_fmt(evsel);
if (fmt) {
struct syscall_fmt *scfmt = syscall_fmt__find(name);
const struct syscall_fmt *scfmt = syscall_fmt__find(name);
if (scfmt) {
int skip = 0;
@ -4525,7 +4546,7 @@ static int trace__parse_events_option(const struct option *opt, const char *str,
int len = strlen(str) + 1, err = -1, list, idx;
char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
char group_name[PATH_MAX];
struct syscall_fmt *fmt;
const struct syscall_fmt *fmt;
if (strace_groups_dir == NULL)
return -1;
@ -4591,8 +4612,11 @@ do_concat:
err = 0;
if (lists[0]) {
struct parse_events_option_args parse_events_option_args = {
.evlistp = &trace->evlist,
};
struct option o = {
.value = &trace->evlist,
.value = &parse_events_option_args,
};
err = parse_events_option(&o, lists[0], 0);
}

View File

@ -1,113 +1,121 @@
#!/bin/sh
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
FILES='
include/uapi/linux/const.h
include/uapi/drm/drm.h
include/uapi/drm/i915_drm.h
include/uapi/linux/fadvise.h
include/uapi/linux/fcntl.h
include/uapi/linux/fs.h
include/uapi/linux/fscrypt.h
include/uapi/linux/kcmp.h
include/uapi/linux/kvm.h
include/uapi/linux/in.h
include/uapi/linux/mount.h
include/uapi/linux/openat2.h
include/uapi/linux/perf_event.h
include/uapi/linux/prctl.h
include/uapi/linux/sched.h
include/uapi/linux/stat.h
include/uapi/linux/usbdevice_fs.h
include/uapi/linux/vhost.h
include/uapi/sound/asound.h
include/linux/bits.h
include/vdso/bits.h
include/linux/const.h
include/vdso/const.h
include/linux/hash.h
include/linux/list-sort.h
include/uapi/linux/hw_breakpoint.h
arch/x86/include/asm/disabled-features.h
arch/x86/include/asm/required-features.h
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/inat_types.h
arch/x86/include/asm/emulate_prefix.h
arch/x86/include/asm/irq_vectors.h
arch/x86/include/asm/msr-index.h
arch/x86/include/uapi/asm/prctl.h
arch/x86/lib/x86-opcode-map.txt
arch/x86/tools/gen-insn-attr-x86.awk
arch/arm/include/uapi/asm/perf_regs.h
arch/arm64/include/uapi/asm/perf_regs.h
arch/loongarch/include/uapi/asm/perf_regs.h
arch/mips/include/uapi/asm/perf_regs.h
arch/powerpc/include/uapi/asm/perf_regs.h
arch/s390/include/uapi/asm/perf_regs.h
arch/x86/include/uapi/asm/perf_regs.h
arch/x86/include/uapi/asm/kvm.h
arch/x86/include/uapi/asm/kvm_perf.h
arch/x86/include/uapi/asm/svm.h
arch/x86/include/uapi/asm/unistd.h
arch/x86/include/uapi/asm/vmx.h
arch/powerpc/include/uapi/asm/kvm.h
arch/s390/include/uapi/asm/kvm.h
arch/s390/include/uapi/asm/kvm_perf.h
arch/s390/include/uapi/asm/sie.h
arch/arm/include/uapi/asm/kvm.h
arch/arm64/include/uapi/asm/kvm.h
arch/arm64/include/uapi/asm/unistd.h
arch/alpha/include/uapi/asm/errno.h
arch/mips/include/asm/errno.h
arch/mips/include/uapi/asm/errno.h
arch/parisc/include/uapi/asm/errno.h
arch/powerpc/include/uapi/asm/errno.h
arch/sparc/include/uapi/asm/errno.h
arch/x86/include/uapi/asm/errno.h
include/asm-generic/bitops/arch_hweight.h
include/asm-generic/bitops/const_hweight.h
include/asm-generic/bitops/__fls.h
include/asm-generic/bitops/fls.h
include/asm-generic/bitops/fls64.h
include/linux/coresight-pmu.h
include/uapi/asm-generic/errno.h
include/uapi/asm-generic/errno-base.h
include/uapi/asm-generic/ioctls.h
include/uapi/asm-generic/mman-common.h
include/uapi/asm-generic/unistd.h
'
YELLOW='\033[0;33m'
NC='\033[0m' # No Color
SYNC_CHECK_FILES='
arch/x86/include/asm/inat.h
arch/x86/include/asm/insn.h
arch/x86/lib/inat.c
arch/x86/lib/insn.c
'
declare -a FILES
FILES=(
"include/uapi/linux/const.h"
"include/uapi/drm/drm.h"
"include/uapi/drm/i915_drm.h"
"include/uapi/linux/fadvise.h"
"include/uapi/linux/fcntl.h"
"include/uapi/linux/fs.h"
"include/uapi/linux/fscrypt.h"
"include/uapi/linux/kcmp.h"
"include/uapi/linux/kvm.h"
"include/uapi/linux/in.h"
"include/uapi/linux/mount.h"
"include/uapi/linux/openat2.h"
"include/uapi/linux/perf_event.h"
"include/uapi/linux/prctl.h"
"include/uapi/linux/sched.h"
"include/uapi/linux/stat.h"
"include/uapi/linux/usbdevice_fs.h"
"include/uapi/linux/vhost.h"
"include/uapi/sound/asound.h"
"include/linux/bits.h"
"include/vdso/bits.h"
"include/linux/const.h"
"include/vdso/const.h"
"include/linux/hash.h"
"include/linux/list-sort.h"
"include/uapi/linux/hw_breakpoint.h"
"arch/x86/include/asm/disabled-features.h"
"arch/x86/include/asm/required-features.h"
"arch/x86/include/asm/cpufeatures.h"
"arch/x86/include/asm/inat_types.h"
"arch/x86/include/asm/emulate_prefix.h"
"arch/x86/include/asm/irq_vectors.h"
"arch/x86/include/asm/msr-index.h"
"arch/x86/include/uapi/asm/prctl.h"
"arch/x86/lib/x86-opcode-map.txt"
"arch/x86/tools/gen-insn-attr-x86.awk"
"arch/arm/include/uapi/asm/perf_regs.h"
"arch/arm64/include/uapi/asm/perf_regs.h"
"arch/loongarch/include/uapi/asm/perf_regs.h"
"arch/mips/include/uapi/asm/perf_regs.h"
"arch/powerpc/include/uapi/asm/perf_regs.h"
"arch/s390/include/uapi/asm/perf_regs.h"
"arch/x86/include/uapi/asm/perf_regs.h"
"arch/x86/include/uapi/asm/kvm.h"
"arch/x86/include/uapi/asm/kvm_perf.h"
"arch/x86/include/uapi/asm/svm.h"
"arch/x86/include/uapi/asm/unistd.h"
"arch/x86/include/uapi/asm/vmx.h"
"arch/powerpc/include/uapi/asm/kvm.h"
"arch/s390/include/uapi/asm/kvm.h"
"arch/s390/include/uapi/asm/kvm_perf.h"
"arch/s390/include/uapi/asm/sie.h"
"arch/arm/include/uapi/asm/kvm.h"
"arch/arm64/include/uapi/asm/kvm.h"
"arch/arm64/include/uapi/asm/unistd.h"
"arch/alpha/include/uapi/asm/errno.h"
"arch/mips/include/asm/errno.h"
"arch/mips/include/uapi/asm/errno.h"
"arch/parisc/include/uapi/asm/errno.h"
"arch/powerpc/include/uapi/asm/errno.h"
"arch/sparc/include/uapi/asm/errno.h"
"arch/x86/include/uapi/asm/errno.h"
"include/asm-generic/bitops/arch_hweight.h"
"include/asm-generic/bitops/const_hweight.h"
"include/asm-generic/bitops/__fls.h"
"include/asm-generic/bitops/fls.h"
"include/asm-generic/bitops/fls64.h"
"include/linux/coresight-pmu.h"
"include/uapi/asm-generic/errno.h"
"include/uapi/asm-generic/errno-base.h"
"include/uapi/asm-generic/ioctls.h"
"include/uapi/asm-generic/mman-common.h"
"include/uapi/asm-generic/unistd.h"
)
declare -a SYNC_CHECK_FILES
SYNC_CHECK_FILES=(
"arch/x86/include/asm/inat.h"
"arch/x86/include/asm/insn.h"
"arch/x86/lib/inat.c"
"arch/x86/lib/insn.c"
)
# These copies are under tools/perf/trace/beauty/ as they are not used to in
# building object files only by scripts in tools/perf/trace/beauty/ to generate
# tables that then gets included in .c files for things like id->string syscall
# tables (and the reverse lookup as well: string -> id)
BEAUTY_FILES='
include/linux/socket.h
'
declare -a BEAUTY_FILES
BEAUTY_FILES=(
"include/linux/socket.h"
)
declare -a FAILURES
check_2 () {
file1=$1
file2=$2
tools_file=$1
orig_file=$2
shift
shift
cmd="diff $* $file1 $file2 > /dev/null"
cmd="diff $* $tools_file $orig_file > /dev/null"
test -f $file2 && {
eval $cmd || {
echo "Warning: Kernel ABI header at '$file1' differs from latest version at '$file2'" >&2
echo diff -u $file1 $file2
}
}
if [ -f "$orig_file" ] && ! eval "$cmd"
then
FAILURES+=(
"$tools_file $orig_file"
)
fi
}
check () {
@ -115,7 +123,7 @@ check () {
shift
check_2 tools/$file $file $*
check_2 "tools/$file" "$file" $*
}
beauty_check () {
@ -123,23 +131,29 @@ beauty_check () {
shift
check_2 tools/perf/trace/beauty/$file $file $*
check_2 "tools/perf/trace/beauty/$file" "$file" $*
}
# Check if we have the kernel headers (tools/perf/../../include), else
# we're probably on a detached tarball, so no point in trying to check
# differences.
test -d ../../include || exit 0
if ! [ -d ../../include ]
then
echo -e "${YELLOW}Warning${NC}: Skipped check-headers due to missing ../../include"
exit 0
fi
cd ../..
# simple diff check
for i in $FILES; do
check $i -B
for i in "${FILES[@]}"
do
check "$i" -B
done
for i in $SYNC_CHECK_FILES; do
check $i '-I "^.*\/\*.*__ignore_sync_check__.*\*\/.*$"'
for i in "${SYNC_CHECK_FILES[@]}"
do
check "$i" '-I "^.*\/\*.*__ignore_sync_check__.*\*\/.*$"'
done
# diff with extra ignore lines
@ -160,8 +174,9 @@ check_2 tools/perf/arch/powerpc/entry/syscalls/syscall.tbl arch/powerpc/kernel/s
check_2 tools/perf/arch/s390/entry/syscalls/syscall.tbl arch/s390/kernel/syscalls/syscall.tbl
check_2 tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl arch/mips/kernel/syscalls/syscall_n64.tbl
for i in $BEAUTY_FILES; do
beauty_check $i -B
for i in "${BEAUTY_FILES[@]}"
do
beauty_check "$i" -B
done
# check duplicated library files
@ -169,3 +184,12 @@ check_2 tools/perf/util/hashmap.h tools/lib/bpf/hashmap.h
check_2 tools/perf/util/hashmap.c tools/lib/bpf/hashmap.c
cd tools/perf
if [ ${#FAILURES[@]} -gt 0 ]
then
echo -e "${YELLOW}Warning${NC}: Kernel ABI header differences:"
for i in "${FAILURES[@]}"
do
echo " diff -u $i"
done
fi

View File

@ -0,0 +1,17 @@
[
{
"ArchStdEvent": "BR_IMMED_SPEC"
},
{
"ArchStdEvent": "BR_RETURN_SPEC"
},
{
"ArchStdEvent": "BR_INDIRECT_SPEC"
},
{
"ArchStdEvent": "BR_MIS_PRED"
},
{
"ArchStdEvent": "BR_PRED"
}
]

View File

@ -0,0 +1,32 @@
[
{
"ArchStdEvent": "CPU_CYCLES"
},
{
"ArchStdEvent": "BUS_CYCLES"
},
{
"ArchStdEvent": "BUS_ACCESS_RD"
},
{
"ArchStdEvent": "BUS_ACCESS_WR"
},
{
"ArchStdEvent": "BUS_ACCESS_SHARED"
},
{
"ArchStdEvent": "BUS_ACCESS_NOT_SHARED"
},
{
"ArchStdEvent": "BUS_ACCESS_NORMAL"
},
{
"ArchStdEvent": "BUS_ACCESS_PERIPH"
},
{
"ArchStdEvent": "BUS_ACCESS"
},
{
"ArchStdEvent": "CNT_CYCLES"
}
]

View File

@ -0,0 +1,104 @@
[
{
"ArchStdEvent": "L1D_CACHE_RD"
},
{
"ArchStdEvent": "L1D_CACHE_WR"
},
{
"ArchStdEvent": "L1D_CACHE_REFILL_RD"
},
{
"ArchStdEvent": "L1D_CACHE_INVAL"
},
{
"ArchStdEvent": "L1D_TLB_REFILL_RD"
},
{
"ArchStdEvent": "L1D_TLB_REFILL_WR"
},
{
"ArchStdEvent": "L2D_CACHE_RD"
},
{
"ArchStdEvent": "L2D_CACHE_WR"
},
{
"ArchStdEvent": "L2D_CACHE_REFILL_RD"
},
{
"ArchStdEvent": "L2D_CACHE_REFILL_WR"
},
{
"ArchStdEvent": "L2D_CACHE_WB_VICTIM"
},
{
"ArchStdEvent": "L2D_CACHE_WB_CLEAN"
},
{
"ArchStdEvent": "L2D_CACHE_INVAL"
},
{
"ArchStdEvent": "L1I_CACHE_REFILL"
},
{
"ArchStdEvent": "L1I_TLB_REFILL"
},
{
"ArchStdEvent": "L1D_CACHE_REFILL"
},
{
"ArchStdEvent": "L1D_CACHE"
},
{
"ArchStdEvent": "L1D_TLB_REFILL"
},
{
"ArchStdEvent": "L1I_CACHE"
},
{
"ArchStdEvent": "L2D_CACHE"
},
{
"ArchStdEvent": "L2D_CACHE_REFILL"
},
{
"ArchStdEvent": "L2D_CACHE_WB"
},
{
"ArchStdEvent": "L1D_TLB"
},
{
"ArchStdEvent": "L1I_TLB"
},
{
"ArchStdEvent": "L2D_TLB_REFILL"
},
{
"ArchStdEvent": "L2I_TLB_REFILL"
},
{
"ArchStdEvent": "L2D_TLB"
},
{
"ArchStdEvent": "L2I_TLB"
},
{
"ArchStdEvent": "DTLB_WALK"
},
{
"ArchStdEvent": "ITLB_WALK"
},
{
"ArchStdEvent": "L1D_CACHE_LMISS_RD"
},
{
"ArchStdEvent": "L1D_CACHE_LMISS"
},
{
"ArchStdEvent": "L1I_CACHE_LMISS"
},
{
"ArchStdEvent": "L2D_CACHE_LMISS_RD"
}
]

View File

@ -0,0 +1,698 @@
[
{
"PublicDescription": "Level 2 prefetch requests, refilled to L2 cache",
"EventCode": "0x10A",
"EventName": "L2_PREFETCH_REFILL",
"BriefDescription": "Level 2 prefetch requests, refilled to L2 cache"
},
{
"PublicDescription": "Level 2 prefetch requests, late",
"EventCode": "0x10B",
"EventName": "L2_PREFETCH_UPGRADE",
"BriefDescription": "Level 2 prefetch requests, late"
},
{
"PublicDescription": "Predictable branch speculatively executed that hit any level of BTB",
"EventCode": "0x110",
"EventName": "BPU_HIT_BTB",
"BriefDescription": "Predictable branch speculatively executed that hit any level of BTB"
},
{
"PublicDescription": "Predictable conditional branch speculatively executed that hit any level of BTB",
"EventCode": "0x111",
"EventName": "BPU_CONDITIONAL_BRANCH_HIT_BTB",
"BriefDescription": "Predictable conditional branch speculatively executed that hit any level of BTB"
},
{
"PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the indirect predictor",
"EventCode": "0x112",
"EventName": "BPU_HIT_INDIRECT_PREDICTOR",
"BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the indirect predictor"
},
{
"PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the return predictor",
"EventCode": "0x113",
"EventName": "BPU_HIT_RSB",
"BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the return predictor"
},
{
"PublicDescription": "Predictable unconditional branch speculatively executed that did not hit any level of BTB",
"EventCode": "0x114",
"EventName": "BPU_UNCONDITIONAL_BRANCH_MISS_BTB",
"BriefDescription": "Predictable unconditional branch speculatively executed that did not hit any level of BTB"
},
{
"PublicDescription": "Predictable branch speculatively executed, unpredicted",
"EventCode": "0x115",
"EventName": "BPU_BRANCH_NO_HIT",
"BriefDescription": "Predictable branch speculatively executed, unpredicted"
},
{
"PublicDescription": "Predictable branch speculatively executed that hit any level of BTB that mispredict",
"EventCode": "0x116",
"EventName": "BPU_HIT_BTB_AND_MISPREDICT",
"BriefDescription": "Predictable branch speculatively executed that hit any level of BTB that mispredict"
},
{
"PublicDescription": "Predictable conditional branch speculatively executed that hit any level of BTB that (direction) mispredict",
"EventCode": "0x117",
"EventName": "BPU_CONDITIONAL_BRANCH_HIT_BTB_AND_MISPREDICT",
"BriefDescription": "Predictable conditional branch speculatively executed that hit any level of BTB that (direction) mispredict"
},
{
"PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the indirect predictor that mispredict",
"EventCode": "0x118",
"EventName": "BPU_INDIRECT_BRANCH_HIT_BTB_AND_MISPREDICT",
"BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the indirect predictor that mispredict"
},
{
"PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the return predictor that mispredict",
"EventCode": "0x119",
"EventName": "BPU_HIT_RSB_AND_MISPREDICT",
"BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the return predictor that mispredict"
},
{
"PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the overflow/underflow return predictor that mispredict",
"EventCode": "0x11a",
"EventName": "BPU_MISS_RSB_AND_MISPREDICT",
"BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the overflow/underflow return predictor that mispredict"
},
{
"PublicDescription": "Predictable branch speculatively executed, unpredicted, that mispredict",
"EventCode": "0x11b",
"EventName": "BPU_NO_PREDICTION_MISPREDICT",
"BriefDescription": "Predictable branch speculatively executed, unpredicted, that mispredict"
},
{
"PublicDescription": "Predictable branch speculatively executed, unpredicted, that mispredict",
"EventCode": "0x11c",
"EventName": "BPU_BTB_UPDATE",
"BriefDescription": "Predictable branch speculatively executed, unpredicted, that mispredict"
},
{
"PublicDescription": "Count predict pipe stalls due to speculative return address predictor full",
"EventCode": "0x11d",
"EventName": "BPU_RSB_FULL_STALL",
"BriefDescription": "Count predict pipe stalls due to speculative return address predictor full"
},
{
"PublicDescription": "Macro-ops speculatively decoded",
"EventCode": "0x11f",
"EventName": "ICF_INST_SPEC_DECODE",
"BriefDescription": "Macro-ops speculatively decoded"
},
{
"PublicDescription": "Flushes",
"EventCode": "0x120",
"EventName": "GPC_FLUSH",
"BriefDescription": "Flushes"
},
{
"PublicDescription": "Flushes due to memory hazards",
"EventCode": "0x121",
"EventName": "BPU_FLUSH_MEM_FAULT",
"BriefDescription": "Flushes due to memory hazards"
},
{
"PublicDescription": "ETM extout bit 0",
"EventCode": "0x141",
"EventName": "MSC_ETM_EXTOUT0",
"BriefDescription": "ETM extout bit 0"
},
{
"PublicDescription": "ETM extout bit 1",
"EventCode": "0x142",
"EventName": "MSC_ETM_EXTOUT1",
"BriefDescription": "ETM extout bit 1"
},
{
"PublicDescription": "ETM extout bit 2",
"EventCode": "0x143",
"EventName": "MSC_ETM_EXTOUT2",
"BriefDescription": "ETM extout bit 2"
},
{
"PublicDescription": "ETM extout bit 3",
"EventCode": "0x144",
"EventName": "MSC_ETM_EXTOUT3",
"BriefDescription": "ETM extout bit 3"
},
{
"PublicDescription": "Bus request sn",
"EventCode": "0x156",
"EventName": "L2C_SNOOP",
"BriefDescription": "Bus request sn"
},
{
"PublicDescription": "L2 TXDAT LCRD blocked",
"EventCode": "0x169",
"EventName": "L2C_DAT_CRD_STALL",
"BriefDescription": "L2 TXDAT LCRD blocked"
},
{
"PublicDescription": "L2 TXRSP LCRD blocked",
"EventCode": "0x16a",
"EventName": "L2C_RSP_CRD_STALL",
"BriefDescription": "L2 TXRSP LCRD blocked"
},
{
"PublicDescription": "L2 TXREQ LCRD blocked",
"EventCode": "0x16b",
"EventName": "L2C_REQ_CRD_STALL",
"BriefDescription": "L2 TXREQ LCRD blocked"
},
{
"PublicDescription": "Early mispredict",
"EventCode": "0xD100",
"EventName": "ICF_EARLY_MIS_PRED",
"BriefDescription": "Early mispredict"
},
{
"PublicDescription": "FEQ full cycles",
"EventCode": "0xD101",
"EventName": "ICF_FEQ_FULL",
"BriefDescription": "FEQ full cycles"
},
{
"PublicDescription": "Instruction FIFO Full",
"EventCode": "0xD102",
"EventName": "ICF_INST_FIFO_FULL",
"BriefDescription": "Instruction FIFO Full"
},
{
"PublicDescription": "L1I TLB miss",
"EventCode": "0xD103",
"EventName": "L1I_TLB_MISS",
"BriefDescription": "L1I TLB miss"
},
{
"PublicDescription": "ICF sent 0 instructions to IDR this cycle",
"EventCode": "0xD104",
"EventName": "ICF_STALL",
"BriefDescription": "ICF sent 0 instructions to IDR this cycle"
},
{
"PublicDescription": "PC FIFO Full",
"EventCode": "0xD105",
"EventName": "ICF_PC_FIFO_FULL",
"BriefDescription": "PC FIFO Full"
},
{
"PublicDescription": "Stall due to BOB ID",
"EventCode": "0xD200",
"EventName": "IDR_STALL_BOB_ID",
"BriefDescription": "Stall due to BOB ID"
},
{
"PublicDescription": "Dispatch stall due to LOB entries",
"EventCode": "0xD201",
"EventName": "IDR_STALL_LOB_ID",
"BriefDescription": "Dispatch stall due to LOB entries"
},
{
"PublicDescription": "Dispatch stall due to SOB entries",
"EventCode": "0xD202",
"EventName": "IDR_STALL_SOB_ID",
"BriefDescription": "Dispatch stall due to SOB entries"
},
{
"PublicDescription": "Dispatch stall due to IXU scheduler entries",
"EventCode": "0xD203",
"EventName": "IDR_STALL_IXU_SCHED",
"BriefDescription": "Dispatch stall due to IXU scheduler entries"
},
{
"PublicDescription": "Dispatch stall due to FSU scheduler entries",
"EventCode": "0xD204",
"EventName": "IDR_STALL_FSU_SCHED",
"BriefDescription": "Dispatch stall due to FSU scheduler entries"
},
{
"PublicDescription": "Dispatch stall due to ROB entries",
"EventCode": "0xD205",
"EventName": "IDR_STALL_ROB_ID",
"BriefDescription": "Dispatch stall due to ROB entries"
},
{
"PublicDescription": "Dispatch stall due to flush (6 cycles)",
"EventCode": "0xD206",
"EventName": "IDR_STALL_FLUSH",
"BriefDescription": "Dispatch stall due to flush (6 cycles)"
},
{
"PublicDescription": "Dispatch stall due to WFI",
"EventCode": "0xD207",
"EventName": "IDR_STALL_WFI",
"BriefDescription": "Dispatch stall due to WFI"
},
{
"PublicDescription": "Number of SWOB drains triggered by timeout",
"EventCode": "0xD208",
"EventName": "IDR_STALL_SWOB_TIMEOUT",
"BriefDescription": "Number of SWOB drains triggered by timeout"
},
{
"PublicDescription": "Number of SWOB drains triggered by system register or special-purpose register read-after-write or specific special-purpose register writes that cause SWOB drain",
"EventCode": "0xD209",
"EventName": "IDR_STALL_SWOB_RAW",
"BriefDescription": "Number of SWOB drains triggered by system register or special-purpose register read-after-write or specific special-purpose register writes that cause SWOB drain"
},
{
"PublicDescription": "Number of SWOB drains triggered by system register write when SWOB full",
"EventCode": "0xD20A",
"EventName": "IDR_STALL_SWOB_FULL",
"BriefDescription": "Number of SWOB drains triggered by system register write when SWOB full"
},
{
"PublicDescription": "Dispatch stall due to L1 instruction cache miss",
"EventCode": "0xD20B",
"EventName": "STALL_FRONTEND_CACHE",
"BriefDescription": "Dispatch stall due to L1 instruction cache miss"
},
{
"PublicDescription": "Dispatch stall due to L1 instruction TLB miss",
"EventCode": "0xD20C",
"EventName": "STALL_FRONTEND_TLB",
"BriefDescription": "Dispatch stall due to L1 instruction TLB miss"
},
{
"PublicDescription": "Dispatch stall due to L1 data cache miss",
"EventCode": "0xD20D",
"EventName": "STALL_BACKEND_CACHE",
"BriefDescription": "Dispatch stall due to L1 data cache miss"
},
{
"PublicDescription": "Dispatch stall due to L1 data TLB miss",
"EventCode": "0xD20E",
"EventName": "STALL_BACKEND_TLB",
"BriefDescription": "Dispatch stall due to L1 data TLB miss"
},
{
"PublicDescription": "Dispatch stall due to lack of any core resource",
"EventCode": "0xD20F",
"EventName": "STALL_BACKEND_RESOURCE",
"BriefDescription": "Dispatch stall due to lack of any core resource"
},
{
"PublicDescription": "Instructions issued by the scheduler",
"EventCode": "0xD300",
"EventName": "IXU_NUM_UOPS_ISSUED",
"BriefDescription": "Instructions issued by the scheduler"
},
{
"PublicDescription": "Any uop issued was canceled for any reason",
"EventCode": "0xD301",
"EventName": "IXU_ISSUE_CANCEL",
"BriefDescription": "Any uop issued was canceled for any reason"
},
{
"PublicDescription": "A load wakeup to the scheduler has been cancelled",
"EventCode": "0xD302",
"EventName": "IXU_LOAD_CANCEL",
"BriefDescription": "A load wakeup to the scheduler has been cancelled"
},
{
"PublicDescription": "The scheduler had to cancel one slow Uop due to resource conflict",
"EventCode": "0xD303",
"EventName": "IXU_SLOW_CANCEL",
"BriefDescription": "The scheduler had to cancel one slow Uop due to resource conflict"
},
{
"PublicDescription": "Uops issued by the scheduler on IXA",
"EventCode": "0xD304",
"EventName": "IXU_IXA_ISSUED",
"BriefDescription": "Uops issued by the scheduler on IXA"
},
{
"PublicDescription": "Uops issued by the scheduler on IXA Par 0",
"EventCode": "0xD305",
"EventName": "IXU_IXA_PAR0_ISSUED",
"BriefDescription": "Uops issued by the scheduler on IXA Par 0"
},
{
"PublicDescription": "Uops issued by the scheduler on IXA Par 1",
"EventCode": "0xD306",
"EventName": "IXU_IXA_PAR1_ISSUED",
"BriefDescription": "Uops issued by the scheduler on IXA Par 1"
},
{
"PublicDescription": "Uops issued by the scheduler on IXB",
"EventCode": "0xD307",
"EventName": "IXU_IXB_ISSUED",
"BriefDescription": "Uops issued by the scheduler on IXB"
},
{
"PublicDescription": "Uops issued by the scheduler on IXB Par 0",
"EventCode": "0xD308",
"EventName": "IXU_IXB_PAR0_ISSUED",
"BriefDescription": "Uops issued by the scheduler on IXB Par 0"
},
{
"PublicDescription": "Uops issued by the scheduler on IXB Par 1",
"EventCode": "0xD309",
"EventName": "IXU_IXB_PAR1_ISSUED",
"BriefDescription": "Uops issued by the scheduler on IXB Par 1"
},
{
"PublicDescription": "Uops issued by the scheduler on IXC",
"EventCode": "0xD30A",
"EventName": "IXU_IXC_ISSUED",
"BriefDescription": "Uops issued by the scheduler on IXC"
},
{
"PublicDescription": "Uops issued by the scheduler on IXC Par 0",
"EventCode": "0xD30B",
"EventName": "IXU_IXC_PAR0_ISSUED",
"BriefDescription": "Uops issued by the scheduler on IXC Par 0"
},
{
"PublicDescription": "Uops issued by the scheduler on IXC Par 1",
"EventCode": "0xD30C",
"EventName": "IXU_IXC_PAR1_ISSUED",
"BriefDescription": "Uops issued by the scheduler on IXC Par 1"
},
{
"PublicDescription": "Uops issued by the scheduler on IXD",
"EventCode": "0xD30D",
"EventName": "IXU_IXD_ISSUED",
"BriefDescription": "Uops issued by the scheduler on IXD"
},
{
"PublicDescription": "Uops issued by the scheduler on IXD Par 0",
"EventCode": "0xD30E",
"EventName": "IXU_IXD_PAR0_ISSUED",
"BriefDescription": "Uops issued by the scheduler on IXD Par 0"
},
{
"PublicDescription": "Uops issued by the scheduler on IXD Par 1",
"EventCode": "0xD30F",
"EventName": "IXU_IXD_PAR1_ISSUED",
"BriefDescription": "Uops issued by the scheduler on IXD Par 1"
},
{
"PublicDescription": "Uops issued by the FSU scheduler",
"EventCode": "0xD400",
"EventName": "FSU_ISSUED",
"BriefDescription": "Uops issued by the FSU scheduler"
},
{
"PublicDescription": "Uops issued by the scheduler on pipe X",
"EventCode": "0xD401",
"EventName": "FSU_FSX_ISSUED",
"BriefDescription": "Uops issued by the scheduler on pipe X"
},
{
"PublicDescription": "Uops issued by the scheduler on pipe Y",
"EventCode": "0xD402",
"EventName": "FSU_FSY_ISSUED",
"BriefDescription": "Uops issued by the scheduler on pipe Y"
},
{
"PublicDescription": "Uops issued by the scheduler on pipe Z",
"EventCode": "0xD403",
"EventName": "FSU_FSZ_ISSUED",
"BriefDescription": "Uops issued by the scheduler on pipe Z"
},
{
"PublicDescription": "Uops canceled (load cancels)",
"EventCode": "0xD404",
"EventName": "FSU_CANCEL",
"BriefDescription": "Uops canceled (load cancels)"
},
{
"PublicDescription": "Count scheduler stalls due to divide/sqrt",
"EventCode": "0xD405",
"EventName": "FSU_DIV_SQRT_STALL",
"BriefDescription": "Count scheduler stalls due to divide/sqrt"
},
{
"PublicDescription": "Number of SWOB drains",
"EventCode": "0xD500",
"EventName": "GPC_SWOB_DRAIN",
"BriefDescription": "Number of SWOB drains"
},
{
"PublicDescription": "GPC detected a Breakpoint instruction match",
"EventCode": "0xD501",
"EventName": "BREAKPOINT_MATCH",
"BriefDescription": "GPC detected a Breakpoint instruction match"
},
{
"PublicDescription": "L1D TLB miss",
"EventCode": "0xD600",
"EventName": "L1D_TLB_MISS",
"BriefDescription": "L1D TLB miss"
},
{
"PublicDescription": "OFB full cycles",
"EventCode": "0xD601",
"EventName": "OFB_FULL",
"BriefDescription": "OFB full cycles"
},
{
"PublicDescription": "Load satisified from store forwarded data",
"EventCode": "0xD605",
"EventName": "LD_FROM_ST_FWD",
"BriefDescription": "Load satisified from store forwarded data"
},
{
"PublicDescription": "L1 prefetcher, load prefetch requests generated",
"EventCode": "0xD606",
"EventName": "L1_PFETCH_LD_GEN",
"BriefDescription": "L1 prefetcher, load prefetch requests generated"
},
{
"PublicDescription": "L1 prefetcher, load prefetch fills into the L1 cache",
"EventCode": "0xD607",
"EventName": "L1_PFETCH_LD_FILL",
"BriefDescription": "L1 prefetcher, load prefetch fills into the L1 cache"
},
{
"PublicDescription": "L1 prefetcher, load prefetch to L2 generated",
"EventCode": "0xD608",
"EventName": "L1_PFETCH_L2_REQ",
"BriefDescription": "L1 prefetcher, load prefetch to L2 generated"
},
{
"PublicDescription": "L1 prefetcher, distance was reset",
"EventCode": "0xD609",
"EventName": "L1_PFETCH_DIST_RST",
"BriefDescription": "L1 prefetcher, distance was reset"
},
{
"PublicDescription": "L1 prefetcher, distance was increased",
"EventCode": "0xD60A",
"EventName": "L1_PFETCH_DIST_INC",
"BriefDescription": "L1 prefetcher, distance was increased"
},
{
"PublicDescription": "L1 prefetcher, table entry is trained",
"EventCode": "0xD60B",
"EventName": "L1_PFETCH_ENTRY_TRAINED",
"BriefDescription": "L1 prefetcher, table entry is trained"
},
{
"PublicDescription": "Store retirement pipe stall",
"EventCode": "0xD60C",
"EventName": "LSU_ST_RETIRE_STALL",
"BriefDescription": "Store retirement pipe stall"
},
{
"PublicDescription": "LSU detected a Watchpoint data match",
"EventCode": "0xD60D",
"EventName": "WATCHPOINT_MATCH",
"BriefDescription": "LSU detected a Watchpoint data match"
},
{
"PublicDescription": "L2 pipeline replay",
"EventCode": "0xD700",
"EventName": "L2C_PIPE_REPLAY",
"BriefDescription": "L2 pipeline replay"
},
{
"PublicDescription": "L2 refill from I-side miss",
"EventCode": "0xD701",
"EventName": "L2C_INST_REFILL",
"BriefDescription": "L2 refill from I-side miss"
},
{
"PublicDescription": "L2 refill from D-side miss",
"EventCode": "0xD702",
"EventName": "L2C_DATA_REFILL",
"BriefDescription": "L2 refill from D-side miss"
},
{
"PublicDescription": "L2 prefetcher, load prefetch requests generated",
"EventCode": "0xD703",
"EventName": "L2_PREFETCH_REQ",
"BriefDescription": "L2 prefetcher, load prefetch requests generated"
},
{
"PublicDescription": "L2D OTB allocate",
"EventCode": "0xD800",
"EventName": "MMU_D_OTB_ALLOC",
"BriefDescription": "L2D OTB allocate"
},
{
"PublicDescription": "DTLB Translation cache hit on S1L2 walk cache entry",
"EventCode": "0xD801",
"EventName": "MMU_D_TRANS_CACHE_HIT_S1L2_WALK",
"BriefDescription": "DTLB Translation cache hit on S1L2 walk cache entry"
},
{
"PublicDescription": "DTLB Translation cache hit on S1L1 walk cache entry",
"EventCode": "0xD802",
"EventName": "MMU_D_TRANS_CACHE_HIT_S1L1_WALK",
"BriefDescription": "DTLB Translation cache hit on S1L1 walk cache entry"
},
{
"PublicDescription": "DTLB Translation cache hit on S1L0 walk cache entry",
"EventCode": "0xD803",
"EventName": "MMU_D_TRANS_CACHE_HIT_S1L0_WALK",
"BriefDescription": "DTLB Translation cache hit on S1L0 walk cache entry"
},
{
"PublicDescription": "DTLB Translation cache hit on S2L2 walk cache entry",
"EventCode": "0xD804",
"EventName": "MMU_D_TRANS_CACHE_HIT_S2L2_WALK",
"BriefDescription": "DTLB Translation cache hit on S2L2 walk cache entry"
},
{
"PublicDescription": "DTLB Translation cache hit on S2L1 walk cache entry",
"EventCode": "0xD805",
"EventName": "MMU_D_TRANS_CACHE_HIT_S2L1_WALK",
"BriefDescription": "DTLB Translation cache hit on S2L1 walk cache entry"
},
{
"PublicDescription": "DTLB Translation cache hit on S2L0 walk cache entry",
"EventCode": "0xD806",
"EventName": "MMU_D_TRANS_CACHE_HIT_S2L0_WALK",
"BriefDescription": "DTLB Translation cache hit on S2L0 walk cache entry"
},
{
"PublicDescription": "D-side S1 Page walk cache lookup",
"EventCode": "0xD807",
"EventName": "MMU_D_S1_WALK_CACHE_LOOKUP",
"BriefDescription": "D-side S1 Page walk cache lookup"
},
{
"PublicDescription": "D-side S1 Page walk cache refill",
"EventCode": "0xD808",
"EventName": "MMU_D_S1_WALK_CACHE_REFILL",
"BriefDescription": "D-side S1 Page walk cache refill"
},
{
"PublicDescription": "D-side S2 Page walk cache lookup",
"EventCode": "0xD809",
"EventName": "MMU_D_S2_WALK_CACHE_LOOKUP",
"BriefDescription": "D-side S2 Page walk cache lookup"
},
{
"PublicDescription": "D-side S2 Page walk cache refill",
"EventCode": "0xD80A",
"EventName": "MMU_D_S2_WALK_CACHE_REFILL",
"BriefDescription": "D-side S2 Page walk cache refill"
},
{
"PublicDescription": "D-side Stage1 tablewalk fault",
"EventCode": "0xD80B",
"EventName": "MMU_D_S1_WALK_FAULT",
"BriefDescription": "D-side Stage1 tablewalk fault"
},
{
"PublicDescription": "D-side Stage2 tablewalk fault",
"EventCode": "0xD80C",
"EventName": "MMU_D_S2_WALK_FAULT",
"BriefDescription": "D-side Stage2 tablewalk fault"
},
{
"PublicDescription": "D-side Tablewalk steps or descriptor fetches",
"EventCode": "0xD80D",
"EventName": "MMU_D_WALK_STEPS",
"BriefDescription": "D-side Tablewalk steps or descriptor fetches"
},
{
"PublicDescription": "L2I OTB allocate",
"EventCode": "0xD900",
"EventName": "MMU_I_OTB_ALLOC",
"BriefDescription": "L2I OTB allocate"
},
{
"PublicDescription": "ITLB Translation cache hit on S1L2 walk cache entry",
"EventCode": "0xD901",
"EventName": "MMU_I_TRANS_CACHE_HIT_S1L2_WALK",
"BriefDescription": "ITLB Translation cache hit on S1L2 walk cache entry"
},
{
"PublicDescription": "ITLB Translation cache hit on S1L1 walk cache entry",
"EventCode": "0xD902",
"EventName": "MMU_I_TRANS_CACHE_HIT_S1L1_WALK",
"BriefDescription": "ITLB Translation cache hit on S1L1 walk cache entry"
},
{
"PublicDescription": "ITLB Translation cache hit on S1L0 walk cache entry",
"EventCode": "0xD903",
"EventName": "MMU_I_TRANS_CACHE_HIT_S1L0_WALK",
"BriefDescription": "ITLB Translation cache hit on S1L0 walk cache entry"
},
{
"PublicDescription": "ITLB Translation cache hit on S2L2 walk cache entry",
"EventCode": "0xD904",
"EventName": "MMU_I_TRANS_CACHE_HIT_S2L2_WALK",
"BriefDescription": "ITLB Translation cache hit on S2L2 walk cache entry"
},
{
"PublicDescription": "ITLB Translation cache hit on S2L1 walk cache entry",
"EventCode": "0xD905",
"EventName": "MMU_I_TRANS_CACHE_HIT_S2L1_WALK",
"BriefDescription": "ITLB Translation cache hit on S2L1 walk cache entry"
},
{
"PublicDescription": "ITLB Translation cache hit on S2L0 walk cache entry",
"EventCode": "0xD906",
"EventName": "MMU_I_TRANS_CACHE_HIT_S2L0_WALK",
"BriefDescription": "ITLB Translation cache hit on S2L0 walk cache entry"
},
{
"PublicDescription": "I-side S1 Page walk cache lookup",
"EventCode": "0xD907",
"EventName": "MMU_I_S1_WALK_CACHE_LOOKUP",
"BriefDescription": "I-side S1 Page walk cache lookup"
},
{
"PublicDescription": "I-side S1 Page walk cache refill",
"EventCode": "0xD908",
"EventName": "MMU_I_S1_WALK_CACHE_REFILL",
"BriefDescription": "I-side S1 Page walk cache refill"
},
{
"PublicDescription": "I-side S2 Page walk cache lookup",
"EventCode": "0xD909",
"EventName": "MMU_I_S2_WALK_CACHE_LOOKUP",
"BriefDescription": "I-side S2 Page walk cache lookup"
},
{
"PublicDescription": "I-side S2 Page walk cache refill",
"EventCode": "0xD90A",
"EventName": "MMU_I_S2_WALK_CACHE_REFILL",
"BriefDescription": "I-side S2 Page walk cache refill"
},
{
"PublicDescription": "I-side Stage1 tablewalk fault",
"EventCode": "0xD90B",
"EventName": "MMU_I_S1_WALK_FAULT",
"BriefDescription": "I-side Stage1 tablewalk fault"
},
{
"PublicDescription": "I-side Stage2 tablewalk fault",
"EventCode": "0xD90C",
"EventName": "MMU_I_S2_WALK_FAULT",
"BriefDescription": "I-side Stage2 tablewalk fault"
},
{
"PublicDescription": "I-side Tablewalk steps or descriptor fetches",
"EventCode": "0xD90D",
"EventName": "MMU_I_WALK_STEPS",
"BriefDescription": "I-side Tablewalk steps or descriptor fetches"
}
]

View File

@ -0,0 +1,44 @@
[
{
"ArchStdEvent": "EXC_UNDEF"
},
{
"ArchStdEvent": "EXC_SVC"
},
{
"ArchStdEvent": "EXC_PABORT"
},
{
"ArchStdEvent": "EXC_DABORT"
},
{
"ArchStdEvent": "EXC_IRQ"
},
{
"ArchStdEvent": "EXC_FIQ"
},
{
"ArchStdEvent": "EXC_HVC"
},
{
"ArchStdEvent": "EXC_TRAP_PABORT"
},
{
"ArchStdEvent": "EXC_TRAP_DABORT"
},
{
"ArchStdEvent": "EXC_TRAP_OTHER"
},
{
"ArchStdEvent": "EXC_TRAP_IRQ"
},
{
"ArchStdEvent": "EXC_TRAP_FIQ"
},
{
"ArchStdEvent": "EXC_TAKEN"
},
{
"ArchStdEvent": "EXC_RETURN"
}
]

View File

@ -0,0 +1,89 @@
[
{
"ArchStdEvent": "SW_INCR"
},
{
"ArchStdEvent": "ST_RETIRED"
},
{
"ArchStdEvent": "OP_SPEC"
},
{
"ArchStdEvent": "LD_SPEC"
},
{
"ArchStdEvent": "ST_SPEC"
},
{
"ArchStdEvent": "LDST_SPEC"
},
{
"ArchStdEvent": "DP_SPEC"
},
{
"ArchStdEvent": "ASE_SPEC"
},
{
"ArchStdEvent": "VFP_SPEC"
},
{
"ArchStdEvent": "PC_WRITE_SPEC"
},
{
"ArchStdEvent": "BR_IMMED_RETIRED"
},
{
"ArchStdEvent": "BR_RETURN_RETIRED"
},
{
"ArchStdEvent": "CRYPTO_SPEC"
},
{
"ArchStdEvent": "ISB_SPEC"
},
{
"ArchStdEvent": "DSB_SPEC"
},
{
"ArchStdEvent": "DMB_SPEC"
},
{
"ArchStdEvent": "RC_LD_SPEC"
},
{
"ArchStdEvent": "RC_ST_SPEC"
},
{
"ArchStdEvent": "INST_RETIRED"
},
{
"ArchStdEvent": "CID_WRITE_RETIRED"
},
{
"ArchStdEvent": "PC_WRITE_RETIRED"
},
{
"ArchStdEvent": "INST_SPEC"
},
{
"ArchStdEvent": "TTBR_WRITE_RETIRED"
},
{
"ArchStdEvent": "BR_RETIRED"
},
{
"ArchStdEvent": "BR_MIS_PRED_RETIRED"
},
{
"ArchStdEvent": "OP_RETIRED"
},
{
"ArchStdEvent": "OP_SPEC"
},
{
"PublicDescription": "Operation speculatively executed, NOP",
"EventCode": "0x100",
"EventName": "NOP_SPEC",
"BriefDescription": "Speculatively executed, NOP"
}
]

View File

@ -0,0 +1,14 @@
[
{
"ArchStdEvent": "LDREX_SPEC"
},
{
"ArchStdEvent": "STREX_PASS_SPEC"
},
{
"ArchStdEvent": "STREX_FAIL_SPEC"
},
{
"ArchStdEvent": "STREX_SPEC"
}
]

View File

@ -0,0 +1,44 @@
[
{
"ArchStdEvent": "LD_RETIRED"
},
{
"ArchStdEvent": "MEM_ACCESS_RD"
},
{
"ArchStdEvent": "MEM_ACCESS_WR"
},
{
"ArchStdEvent": "UNALIGNED_LD_SPEC"
},
{
"ArchStdEvent": "UNALIGNED_ST_SPEC"
},
{
"ArchStdEvent": "UNALIGNED_LDST_SPEC"
},
{
"ArchStdEvent": "LD_ALIGN_LAT"
},
{
"ArchStdEvent": "ST_ALIGN_LAT"
},
{
"ArchStdEvent": "MEM_ACCESS"
},
{
"ArchStdEvent": "MEMORY_ERROR"
},
{
"ArchStdEvent": "LDST_ALIGN_LAT"
},
{
"ArchStdEvent": "MEM_ACCESS_CHECKED"
},
{
"ArchStdEvent": "MEM_ACCESS_CHECKED_RD"
},
{
"ArchStdEvent": "MEM_ACCESS_CHECKED_WR"
}
]

View File

@ -0,0 +1,23 @@
[
{
"ArchStdEvent": "STALL_FRONTEND"
},
{
"ArchStdEvent": "STALL_BACKEND"
},
{
"ArchStdEvent": "STALL"
},
{
"ArchStdEvent": "STALL_SLOT_BACKEND"
},
{
"ArchStdEvent": "STALL_SLOT_FRONTEND"
},
{
"ArchStdEvent": "STALL_SLOT"
},
{
"ArchStdEvent": "STALL_BACKEND_MEM"
}
]

View File

@ -0,0 +1,14 @@
[
{
"ArchStdEvent": "SAMPLE_POP"
},
{
"ArchStdEvent": "SAMPLE_FEED"
},
{
"ArchStdEvent": "SAMPLE_FILTRATE"
},
{
"ArchStdEvent": "SAMPLE_COLLISION"
}
]

View File

@ -3,28 +3,32 @@
"MetricExpr": "FETCH_BUBBLE / (4 * CPU_CYCLES)",
"PublicDescription": "Frontend bound L1 topdown metric",
"BriefDescription": "Frontend bound L1 topdown metric",
"MetricGroup": "TopDownL1",
"DefaultMetricgroupName": "TopDownL1",
"MetricGroup": "Default;TopDownL1",
"MetricName": "frontend_bound"
},
{
"MetricExpr": "(INST_SPEC - INST_RETIRED) / (4 * CPU_CYCLES)",
"PublicDescription": "Bad Speculation L1 topdown metric",
"BriefDescription": "Bad Speculation L1 topdown metric",
"MetricGroup": "TopDownL1",
"DefaultMetricgroupName": "TopDownL1",
"MetricGroup": "Default;TopDownL1",
"MetricName": "bad_speculation"
},
{
"MetricExpr": "INST_RETIRED / (CPU_CYCLES * 4)",
"PublicDescription": "Retiring L1 topdown metric",
"BriefDescription": "Retiring L1 topdown metric",
"MetricGroup": "TopDownL1",
"DefaultMetricgroupName": "TopDownL1",
"MetricGroup": "Default;TopDownL1",
"MetricName": "retiring"
},
{
"MetricExpr": "1 - (frontend_bound + bad_speculation + retiring)",
"PublicDescription": "Backend Bound L1 topdown metric",
"BriefDescription": "Backend Bound L1 topdown metric",
"MetricGroup": "TopDownL1",
"DefaultMetricgroupName": "TopDownL1",
"MetricGroup": "Default;TopDownL1",
"MetricName": "backend_bound"
},
{

View File

@ -41,3 +41,4 @@
0x00000000460f0010,v1,fujitsu/a64fx,core
0x00000000480fd010,v1,hisilicon/hip08,core
0x00000000500f0000,v1,ampere/emag,core
0x00000000c00fac30,v1,ampere/ampereone,core

1 # Format:
41 0x00000000460f0010,v1,fujitsu/a64fx,core
42 0x00000000480fd010,v1,hisilicon/hip08,core
43 0x00000000500f0000,v1,ampere/emag,core
44 0x00000000c00fac30,v1,ampere/ampereone,core

View File

@ -2,28 +2,32 @@
{
"MetricExpr": "stall_slot_frontend / (#slots * cpu_cycles)",
"BriefDescription": "Frontend bound L1 topdown metric",
"MetricGroup": "TopdownL1",
"DefaultMetricgroupName": "TopdownL1",
"MetricGroup": "Default;TopdownL1",
"MetricName": "frontend_bound",
"ScaleUnit": "100%"
},
{
"MetricExpr": "(1 - op_retired / op_spec) * (1 - stall_slot / (#slots * cpu_cycles))",
"BriefDescription": "Bad speculation L1 topdown metric",
"MetricGroup": "TopdownL1",
"DefaultMetricgroupName": "TopdownL1",
"MetricGroup": "Default;TopdownL1",
"MetricName": "bad_speculation",
"ScaleUnit": "100%"
},
{
"MetricExpr": "(op_retired / op_spec) * (1 - stall_slot / (#slots * cpu_cycles))",
"BriefDescription": "Retiring L1 topdown metric",
"MetricGroup": "TopdownL1",
"DefaultMetricgroupName": "TopdownL1",
"MetricGroup": "Default;TopdownL1",
"MetricName": "retiring",
"ScaleUnit": "100%"
},
{
"MetricExpr": "stall_slot_backend / (#slots * cpu_cycles)",
"BriefDescription": "Backend Bound L1 topdown metric",
"MetricGroup": "TopdownL1",
"DefaultMetricgroupName": "TopdownL1",
"MetricGroup": "Default;TopdownL1",
"MetricName": "backend_bound",
"ScaleUnit": "100%"
}

File diff suppressed because it is too large Load Diff

View File

@ -1017,6 +1017,15 @@
"UMask": "0x1",
"Unit": "cpu_core"
},
{
"BriefDescription": "Counts bus locks, accounts for cache line split locks and UC locks.",
"EventCode": "0x2c",
"EventName": "SQ_MISC.BUS_LOCK",
"PublicDescription": "Counts the more expensive bus lock needed to enforce cache coherency for certain memory accesses that need to be done atomically. Can be created by issuing an atomic instruction (via the LOCK prefix) which causes a cache line split or accesses uncacheable memory.",
"SampleAfterValue": "100003",
"UMask": "0x10",
"Unit": "cpu_core"
},
{
"BriefDescription": "Number of PREFETCHNTA instructions executed.",
"EventCode": "0x40",

Some files were not shown because too many files have changed in this diff Show More