perf tools changes for v6.13

perf record
 -----------
 * Enable leader sampling for inherited task events.  It was supported
   only for system-wide events but the kernel started to support such a
   setup since v6.12.
 
   This is to reduce the number of PMU interrupts.  The samples of the
   leader event will contain counts of other events and no samples will
   be generated for the other member events.
 
     $ perf record -e '{cycles,instructions}:S'  ${MYPROG}
 
 perf report
 -----------
 * Fix --branch-history option to display more branch-related information
   like prediction, abort and cycles which is available on Intel machines.
 
     $ perf record -bg -- perf test -w brstack
 
     $ perf report --branch-history
     ...
     #
     # Overhead  Source:Line               Symbol          Shared Object         Predicted  Abort  Cycles  IPC   [IPC Coverage]
     # ........  ........................  ..............  ....................  .........  .....  ......  ....................
     #
          8.17%  copy_page_64.S:19         [k] copy_page   [kernel.kallsyms]     50.0%      0      5       -      -
                 |
                 ---xas_load xarray.h:171
                    |
                    |--5.68%--xas_load xarray.c:245 (cycles:1)
                    |          xas_load xarray.c:242
                    |          xas_load xarray.h:1260 (cycles:1)
                    |          xas_descend xarray.c:146
                    |          xas_load xarray.c:244 (cycles:2)
                    |          xas_load xarray.c:245
                    |          xas_descend xarray.c:218 (cycles:10)
     ...
 
 perf stat
 ---------
 * Add HWMON PMU support.  The HWMON provides various system information
   like CPU/GPU temperature, fan speed and so on.  Expose them as PMU
   events so that users can see the values using perf stat commands.
 
     $ perf stat -e temp_cpu,fan1 true
 
      Performance counter stats for 'true':
 
                  60.00 'C   temp_cpu
                      0 rpm  fan1
 
            0.000745382 seconds time elapsed
 
            0.000883000 seconds user
            0.000000000 seconds sys
 
 * Display metric threshold in JSON output.  Some metrics define
   thresholds to classify value ranges.  It used to be in a different
   color but it won't work for JSON.  Add "metric-threshold" field to
   the JSON that can be one of "good", "less good", "nearly bad" and
   "bad".
 
     # perf stat -a -M TopdownL1 -j true
     {"counter-value" : "18693525.000000", "unit" : "", "event" : "TOPDOWN.SLOTS", "event-runtime" : 5552708, "pcnt-running" : 100.00, "metric-value" : "43.226002", "metric-unit" : "%  tma_backend_bound", "metric-threshold" : "bad"}
     {"metric-value" : "29.212267", "metric-unit" : "%  tma_frontend_bound", "metric-threshold" : "bad"}
     {"metric-value" : "7.138972", "metric-unit" : "%  tma_bad_speculation", "metric-threshold" : "good"}
     {"metric-value" : "20.422759", "metric-unit" : "%  tma_retiring", "metric-threshold" : "good"}
     {"counter-value" : "3817732.000000", "unit" : "", "event" : "topdown-retiring", "event-runtime" : 5552708, "pcnt-running" : 100.00, }
     {"counter-value" : "5472824.000000", "unit" : "", "event" : "topdown-fe-bound", "event-runtime" : 5552708, "pcnt-running" : 100.00, }
     {"counter-value" : "7984780.000000", "unit" : "", "event" : "topdown-be-bound", "event-runtime" : 5552708, "pcnt-running" : 100.00, }
     {"counter-value" : "1418181.000000", "unit" : "", "event" : "topdown-bad-spec", "event-runtime" : 5552708, "pcnt-running" : 100.00, }
     ...
 
 perf sched
 ----------
 * Add -P/--pre-migrations option for 'timehist' sub-command to track
   time a task waited on a run-queue before migrating to a different CPU.
 
     $ perf sched timehist -P
                time    cpu  task name                       wait time  sch delay   run time  pre-mig time
                             [tid/pid]                          (msec)     (msec)     (msec)     (msec)
     --------------- ------  ------------------------------  ---------  ---------  ---------  ---------
       585940.535527 [0000]  perf[584885]                        0.000      0.000      0.000      0.000
       585940.535535 [0000]  migration/0[20]                     0.000      0.002      0.008      0.000
       585940.535559 [0001]  perf[584885]                        0.000      0.000      0.000      0.000
       585940.535563 [0001]  migration/1[25]                     0.000      0.001      0.004      0.000
       585940.535678 [0002]  perf[584885]                        0.000      0.000      0.000      0.000
       585940.535686 [0002]  migration/2[31]                     0.000      0.002      0.008      0.000
       585940.535905 [0001]  <idle>                              0.000      0.000      0.342      0.000
       585940.535938 [0003]  perf[584885]                        0.000      0.000      0.000      0.000
       585940.537048 [0001]  sleep[584886]                       0.000      0.019      1.142      0.001
       585940.537749 [0002]  <idle>                              0.000      0.000      2.062      0.000
     ...
 
 Build
 -----
 * Make libunwind opt-in (LIBUNWIND=1) rather than opt-out.  The perf
   tools are generally built with libelf and libdw which has unwinder
   functionality.  The libunwind support predates it and no need to
   have duplicate unwinders by default.
 
 * Rename NO_DWARF=1 build option to NO_LIBDW=1 in order to clarify it's
   using libdw for handling DWARF information.
 
 Internals
 ---------
 * Do not set exclude_guest bit in the perf_event_attr by default.  This
   was causing a trouble in AMD IBS PMU as it doesn't support the bit.
   The bit will be set when it's needed later by the fallback logic.
   Also update the missing feature detection logic to make sure not clear
   supported bits unnecessarily.
 
 * Run perf test in parallel by default and mark flaky tests "exclusive"
   to run them serially at the end.  Some test numbers are changed but
   the test can complete in less than half the time.
 
 JSON vendor events
 ------------------
 * Add AMD Zen 5 events and metrics.
 
 * Add i.MX91 and i.MX95 DDR metrics
 
 * Fix HiSilicon HIP08 Topdown metric name.
 
 * Support compat events on PowerPC.
 
 Signed-off-by: Namhyung Kim <namhyung@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQSo2x5BnqMqsoHtzsmMstVUGiXMgwUCZ0Qi3gAKCRCMstVUGiXM
 g6NIAP49eoSmQF40u55sJN0J7RpYd+bTgXZkahv0IUCBX98TLwEA2NrK0oUcB84C
 xeanq28/3JxNM/oBpsEvvB8mb/0lGwI=
 =FAVF
 -----END PGP SIGNATURE-----

Merge tag 'perf-tools-for-v6.13-2024-11-24' of git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools

Pull perf tools updates from Namhyung Kim:
 "perf record:

   - Enable leader sampling for inherited task events. It was supported
     only for system-wide events but the kernel started to support such
     a setup since v6.12.

     This is to reduce the number of PMU interrupts. The samples of the
     leader event will contain counts of other events and no samples
     will be generated for the other member events.

       $ perf record -e '{cycles,instructions}:S'  ${MYPROG}

  perf report:

   - Fix --branch-history option to display more branch-related
     information like prediction, abort and cycles which is available
     on Intel machines.

       $ perf record -bg -- perf test -w brstack

       $ perf report --branch-history
       ...
       #
       # Overhead  Source:Line               Symbol          Shared Object         Predicted  Abort  Cycles  IPC   [IPC Coverage]
       # ........  ........................  ..............  ....................  .........  .....  ......  ....................
       #
            8.17%  copy_page_64.S:19         [k] copy_page   [kernel.kallsyms]     50.0%      0      5       -      -
                   |
                   ---xas_load xarray.h:171
                      |
                      |--5.68%--xas_load xarray.c:245 (cycles:1)
                      |          xas_load xarray.c:242
                      |          xas_load xarray.h:1260 (cycles:1)
                      |          xas_descend xarray.c:146
                      |          xas_load xarray.c:244 (cycles:2)
                      |          xas_load xarray.c:245
                      |          xas_descend xarray.c:218 (cycles:10)
       ...

  perf stat:

   - Add HWMON PMU support.

     The HWMON provides various system information like CPU/GPU
     temperature, fan speed and so on. Expose them as PMU events so that
     users can see the values using perf stat commands.

       $ perf stat -e temp_cpu,fan1 true

        Performance counter stats for 'true':

                    60.00 'C   temp_cpu
                        0 rpm  fan1

              0.000745382 seconds time elapsed

              0.000883000 seconds user
              0.000000000 seconds sys

   - Display metric threshold in JSON output.

     Some metrics define thresholds to classify value ranges. It used to
     be in a different color but it won't work for JSON.

     Add "metric-threshold" field to the JSON that can be one of "good",
     "less good", "nearly bad" and "bad".

       # perf stat -a -M TopdownL1 -j true
       {"counter-value" : "18693525.000000", "unit" : "", "event" : "TOPDOWN.SLOTS", "event-runtime" : 5552708, "pcnt-running" : 100.00, "metric-value" : "43.226002", "metric-unit" : "%  tma_backend_bound", "metric-threshold" : "bad"}
       {"metric-value" : "29.212267", "metric-unit" : "%  tma_frontend_bound", "metric-threshold" : "bad"}
       {"metric-value" : "7.138972", "metric-unit" : "%  tma_bad_speculation", "metric-threshold" : "good"}
       {"metric-value" : "20.422759", "metric-unit" : "%  tma_retiring", "metric-threshold" : "good"}
       {"counter-value" : "3817732.000000", "unit" : "", "event" : "topdown-retiring", "event-runtime" : 5552708, "pcnt-running" : 100.00, }
       {"counter-value" : "5472824.000000", "unit" : "", "event" : "topdown-fe-bound", "event-runtime" : 5552708, "pcnt-running" : 100.00, }
       {"counter-value" : "7984780.000000", "unit" : "", "event" : "topdown-be-bound", "event-runtime" : 5552708, "pcnt-running" : 100.00, }
       {"counter-value" : "1418181.000000", "unit" : "", "event" : "topdown-bad-spec", "event-runtime" : 5552708, "pcnt-running" : 100.00, }
       ...

  perf sched:

   - Add -P/--pre-migrations option for 'timehist' sub-command to track
     time a task waited on a run-queue before migrating to a different
     CPU.

       $ perf sched timehist -P
                  time    cpu  task name                       wait time  sch delay   run time  pre-mig time
                               [tid/pid]                          (msec)     (msec)     (msec)     (msec)
       --------------- ------  ------------------------------  ---------  ---------  ---------  ---------
         585940.535527 [0000]  perf[584885]                        0.000      0.000      0.000      0.000
         585940.535535 [0000]  migration/0[20]                     0.000      0.002      0.008      0.000
         585940.535559 [0001]  perf[584885]                        0.000      0.000      0.000      0.000
         585940.535563 [0001]  migration/1[25]                     0.000      0.001      0.004      0.000
         585940.535678 [0002]  perf[584885]                        0.000      0.000      0.000      0.000
         585940.535686 [0002]  migration/2[31]                     0.000      0.002      0.008      0.000
         585940.535905 [0001]  <idle>                              0.000      0.000      0.342      0.000
         585940.535938 [0003]  perf[584885]                        0.000      0.000      0.000      0.000
         585940.537048 [0001]  sleep[584886]                       0.000      0.019      1.142      0.001
         585940.537749 [0002]  <idle>                              0.000      0.000      2.062      0.000
       ...

  Build:

   - Make libunwind opt-in (LIBUNWIND=1) rather than opt-out.

     The perf tools are generally built with libelf and libdw which has
     unwinder functionality. The libunwind support predates it and no
     need to have duplicate unwinders by default.

   - Rename NO_DWARF=1 build option to NO_LIBDW=1 in order to clarify
     it's using libdw for handling DWARF information.

  Internals:

   - Do not set exclude_guest bit in the perf_event_attr by default.

     This was causing a trouble in AMD IBS PMU as it doesn't support the
     bit. The bit will be set when it's needed later by the fallback
     logic. Also update the missing feature detection logic to make sure
     not clear supported bits unnecessarily.

   - Run perf test in parallel by default and mark flaky tests
     "exclusive" to run them serially at the end. Some test numbers are
     changed but the test can complete in less than half the time.

  JSON vendor events:

   - Add AMD Zen 5 events and metrics.

   - Add i.MX91 and i.MX95 DDR metrics

   - Fix HiSilicon HIP08 Topdown metric name.

   - Support compat events on PowerPC"

* tag 'perf-tools-for-v6.13-2024-11-24' of git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools: (232 commits)
  perf tests: Fix hwmon parsing with PMU name test
  perf hwmon_pmu: Ensure hwmon key union is zeroed before use
  perf tests hwmon_pmu: Remove double evlist__delete()
  perf/test: fix perf ftrace test on s390
  perf bpf-filter: Return -ENOMEM directly when pfi allocation fails
  perf test: Correct hwmon test PMU detection
  perf: Remove unused del_perf_probe_events()
  perf pmu: Move pmu_metrics_table__find and remove ARM override
  perf jevents: Add map_for_cpu()
  perf header: Pass a perf_cpu rather than a PMU to get_cpuid_str
  perf header: Avoid transitive PMU includes
  perf arm64 header: Use cpu argument in get_cpuid
  perf header: Refactor get_cpuid to take a CPU for ARM
  perf header: Move is_cpu_online to numa bench
  perf jevents: fix breakage when do perf stat on system metric
  perf test: Add missing __exit calls in tool/hwmon tests
  perf tests: Make leader sampling test work without branch event
  perf util: Remove kernel version deadcode
  perf test shell trace_exit_race: Use --no-comm to avoid cases where COMM isn't resolved
  perf test shell trace_exit_race: Show what went wrong in verbose mode
  ...
This commit is contained in:
Linus Torvalds 2024-11-26 14:54:00 -08:00
commit b50ecc5aca
338 changed files with 9514 additions and 4154 deletions

View File

@ -30,9 +30,7 @@ endef
#
FEATURE_TESTS_BASIC := \
backtrace \
dwarf \
dwarf_getlocations \
dwarf_getcfi \
libdw \
eventfd \
fortify-source \
get_current_dir_name \
@ -61,7 +59,6 @@ FEATURE_TESTS_BASIC := \
reallocarray \
stackprotector-all \
timerfd \
libdw-dwarf-unwind \
zlib \
lzma \
get_cpuid \
@ -121,8 +118,7 @@ ifeq ($(FEATURE_TESTS),all)
endif
FEATURE_DISPLAY ?= \
dwarf \
dwarf_getlocations \
libdw \
glibc \
libbfd \
libbfd-buildid \
@ -134,7 +130,6 @@ FEATURE_DISPLAY ?= \
libpython \
libcrypto \
libunwind \
libdw-dwarf-unwind \
libcapstone \
llvm-perf \
zlib \
@ -234,7 +229,7 @@ endef
#
# generates feature value assignment for name, like:
# $(call feature_assign,dwarf) == feature-dwarf=1
# $(call feature_assign,libdw) == feature-libdw=1
#
feature_assign = feature-$(1)=$(feature-$(1))

View File

@ -5,9 +5,7 @@ FILES= \
test-all.bin \
test-backtrace.bin \
test-bionic.bin \
test-dwarf.bin \
test-dwarf_getlocations.bin \
test-dwarf_getcfi.bin \
test-libdw.bin \
test-eventfd.bin \
test-fortify-source.bin \
test-get_current_dir_name.bin \
@ -53,7 +51,6 @@ FILES= \
test-pthread-barrier.bin \
test-stackprotector-all.bin \
test-timerfd.bin \
test-libdw-dwarf-unwind.bin \
test-libbabeltrace.bin \
test-libcapstone.bin \
test-compile-32.bin \
@ -169,9 +166,9 @@ $(OUTPUT)test-libopencsd.bin:
$(BUILD) # -lopencsd_c_api -lopencsd provided by
# $(FEATURE_CHECK_LDFLAGS-libopencsd)
DWARFLIBS := -ldw
DWLIBS := -ldw
ifeq ($(findstring -static,${LDFLAGS}),-static)
DWARFLIBS += -lelf -lz -llzma -lbz2 -lzstd
DWLIBS += -lelf -lz -llzma -lbz2 -lzstd
LIBDW_VERSION := $(shell $(PKG_CONFIG) --modversion libdw).0.0
LIBDW_VERSION_1 := $(word 1, $(subst ., ,$(LIBDW_VERSION)))
@ -180,21 +177,15 @@ ifeq ($(findstring -static,${LDFLAGS}),-static)
# Elfutils merged libebl.a into libdw.a starting from version 0.177,
# Link libebl.a only if libdw is older than this version.
ifeq ($(shell test $(LIBDW_VERSION_2) -lt 177; echo $$?),0)
DWARFLIBS += -lebl
DWLIBS += -lebl
endif
# Must put -ldl after -lebl for dependency
DWARFLIBS += -ldl
endif
$(OUTPUT)test-dwarf.bin:
$(BUILD) $(DWARFLIBS)
$(OUTPUT)test-dwarf_getlocations.bin:
$(BUILD) $(DWARFLIBS)
$(OUTPUT)test-dwarf_getcfi.bin:
$(BUILD) $(DWARFLIBS)
$(OUTPUT)test-libdw.bin:
$(BUILD) $(DWLIBS)
$(OUTPUT)test-libelf-getphdrnum.bin:
$(BUILD) -lelf
@ -321,9 +312,6 @@ $(OUTPUT)test-backtrace.bin:
$(OUTPUT)test-timerfd.bin:
$(BUILD)
$(OUTPUT)test-libdw-dwarf-unwind.bin:
$(BUILD) # -ldw provided by $(FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind)
$(OUTPUT)test-libbabeltrace.bin:
$(BUILD) # -lbabeltrace provided by $(FEATURE_CHECK_LDFLAGS-libbabeltrace)

View File

@ -38,12 +38,8 @@
# include "test-glibc.c"
#undef main
#define main main_test_dwarf
# include "test-dwarf.c"
#undef main
#define main main_test_dwarf_getlocations
# include "test-dwarf_getlocations.c"
#define main main_test_libdw
# include "test-libdw.c"
#undef main
#define main main_test_eventfd
@ -98,10 +94,6 @@
# include "test-stackprotector-all.c"
#undef main
#define main main_test_libdw_dwarf_unwind
# include "test-libdw-dwarf-unwind.c"
#undef main
#define main main_test_zlib
# include "test-zlib.c"
#undef main
@ -187,8 +179,7 @@ int main(int argc, char *argv[])
main_test_get_current_dir_name();
main_test_gettid();
main_test_glibc();
main_test_dwarf();
main_test_dwarf_getlocations();
main_test_libdw();
main_test_eventfd();
main_test_libelf_getphdrnum();
main_test_libelf_gelf_getnote();
@ -202,7 +193,6 @@ int main(int argc, char *argv[])
main_test_numa_num_possible_cpus();
main_test_timerfd();
main_test_stackprotector_all();
main_test_libdw_dwarf_unwind();
main_test_zlib();
main_test_pthread_attr_setaffinity_np();
main_test_pthread_barrier();

View File

@ -1,11 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <dwarf.h>
#include <elfutils/libdw.h>
#include <elfutils/version.h>
int main(void)
{
Dwarf *dbg = dwarf_begin(0, DWARF_C_READ);
return (long)dbg;
}

View File

@ -1,9 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <stdio.h>
#include <elfutils/libdw.h>
int main(void)
{
Dwarf *dwarf = NULL;
return dwarf_getcfi(dwarf) == NULL;
}

View File

@ -1,13 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <stdlib.h>
#include <elfutils/libdw.h>
int main(void)
{
Dwarf_Addr base, start, end;
Dwarf_Attribute attr;
Dwarf_Op *op;
size_t nops;
ptrdiff_t offset = 0;
return (int)dwarf_getlocations(&attr, offset, &base, &start, &end, &op, &nops);
}

View File

@ -1,14 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <elfutils/libdwfl.h>
int main(void)
{
/*
* This function is guarded via: __nonnull_attribute__ (1, 2).
* Passing '1' as arguments value. This code is never executed,
* only compiled.
*/
dwfl_thread_getframes((void *) 1, (void *) 1, NULL);
return 0;
}

View File

@ -0,0 +1,56 @@
// SPDX-License-Identifier: GPL-2.0
#include <stdlib.h>
#include <dwarf.h>
#include <elfutils/libdw.h>
#include <elfutils/libdwfl.h>
#include <elfutils/version.h>
int test_libdw(void)
{
Dwarf *dbg = dwarf_begin(0, DWARF_C_READ);
return (long)dbg;
}
int test_libdw_unwind(void)
{
/*
* This function is guarded via: __nonnull_attribute__ (1, 2).
* Passing '1' as arguments value. This code is never executed,
* only compiled.
*/
dwfl_thread_getframes((void *) 1, (void *) 1, NULL);
return 0;
}
int test_libdw_getlocations(void)
{
Dwarf_Addr base, start, end;
Dwarf_Attribute attr;
Dwarf_Op *op;
size_t nops;
ptrdiff_t offset = 0;
return (int)dwarf_getlocations(&attr, offset, &base, &start, &end, &op, &nops);
}
int test_libdw_getcfi(void)
{
Dwarf *dwarf = NULL;
return dwarf_getcfi(dwarf) == NULL;
}
int test_elfutils(void)
{
Dwarf_CFI *cfi = NULL;
dwarf_cfi_end(cfi);
return 0;
}
int main(void)
{
return test_libdw() + test_libdw_unwind() + test_libdw_getlocations() +
test_libdw_getcfi() + test_elfutils();
}

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
#include <traceevent/trace-seq.h>
#include <trace-seq.h>
int main(void)
{

View File

@ -189,6 +189,7 @@ static inline ssize_t io__getdelim(struct io *io, char **line_out, size_t *line_
err_out:
free(line);
*line_out = NULL;
*line_len_out = 0;
return -ENOMEM;
}

View File

@ -121,7 +121,7 @@ install-man: all
$(INSTALL) -d -m 755 $(DESTDIR)$(man7dir); \
$(INSTALL) -m 644 $(MAN_7) $(DESTDIR)$(man7dir);
install-html:
install-html: $(MAN_HTML)
$(call QUIET_INSTALL, html) \
$(INSTALL) -d -m 755 $(DESTDIR)$(htmldir); \
$(INSTALL) -m 644 $(MAN_HTML) $(DESTDIR)$(htmldir); \

View File

@ -5,6 +5,7 @@
#include <perf/evsel.h>
#include <perf/cpumap.h>
#include <perf/threadmap.h>
#include <linux/hash.h>
#include <linux/list.h>
#include <internal/evsel.h>
#include <linux/zalloc.h>
@ -23,6 +24,7 @@ void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr,
int idx)
{
INIT_LIST_HEAD(&evsel->node);
INIT_LIST_HEAD(&evsel->per_stream_periods);
evsel->attr = *attr;
evsel->idx = idx;
evsel->leader = evsel;
@ -531,10 +533,56 @@ int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
void perf_evsel__free_id(struct perf_evsel *evsel)
{
struct perf_sample_id_period *pos, *n;
xyarray__delete(evsel->sample_id);
evsel->sample_id = NULL;
zfree(&evsel->id);
evsel->ids = 0;
perf_evsel_for_each_per_thread_period_safe(evsel, n, pos) {
list_del_init(&pos->node);
free(pos);
}
}
bool perf_evsel__attr_has_per_thread_sample_period(struct perf_evsel *evsel)
{
return (evsel->attr.sample_type & PERF_SAMPLE_READ) &&
(evsel->attr.sample_type & PERF_SAMPLE_TID) &&
evsel->attr.inherit;
}
u64 *perf_sample_id__get_period_storage(struct perf_sample_id *sid, u32 tid, bool per_thread)
{
struct hlist_head *head;
struct perf_sample_id_period *res;
int hash;
if (!per_thread)
return &sid->period;
hash = hash_32(tid, PERF_SAMPLE_ID__HLIST_BITS);
head = &sid->periods[hash];
hlist_for_each_entry(res, head, hnode)
if (res->tid == tid)
return &res->period;
if (sid->evsel == NULL)
return NULL;
res = zalloc(sizeof(struct perf_sample_id_period));
if (res == NULL)
return NULL;
INIT_LIST_HEAD(&res->node);
res->tid = tid;
list_add_tail(&res->node, &sid->evsel->per_stream_periods);
hlist_add_head(&res->hnode, &sid->periods[hash]);
return &res->period;
}
void perf_counts_values__scale(struct perf_counts_values *count,

View File

@ -11,6 +11,32 @@
struct perf_thread_map;
struct xyarray;
/**
* The per-thread accumulated period storage node.
*/
struct perf_sample_id_period {
struct list_head node;
struct hlist_node hnode;
/* Holds total ID period value for PERF_SAMPLE_READ processing. */
u64 period;
/* The TID that the values belongs to */
u32 tid;
};
/**
* perf_evsel_for_each_per_thread_period_safe - safely iterate thru all the
* per_stream_periods
* @evlist:perf_evsel instance to iterate
* @item: struct perf_sample_id_period iterator
* @tmp: struct perf_sample_id_period temp iterator
*/
#define perf_evsel_for_each_per_thread_period_safe(evsel, tmp, item) \
list_for_each_entry_safe(item, tmp, &(evsel)->per_stream_periods, node)
#define PERF_SAMPLE_ID__HLIST_BITS 4
#define PERF_SAMPLE_ID__HLIST_SIZE (1 << PERF_SAMPLE_ID__HLIST_BITS)
/*
* Per fd, to map back from PERF_SAMPLE_ID to evsel, only used when there are
* more than one entry in the evlist.
@ -34,8 +60,32 @@ struct perf_sample_id {
pid_t machine_pid;
struct perf_cpu vcpu;
/* Holds total ID period value for PERF_SAMPLE_READ processing. */
u64 period;
/*
* Per-thread, and global event counts are mutually exclusive:
* Whilst it is possible to combine events into a group with differing
* values of PERF_SAMPLE_READ, it is not valid to have inconsistent
* values for `inherit`. Therefore it is not possible to have a
* situation where a per-thread event is sampled as a global event;
* all !inherit groups are global, and all groups where the sampling
* event is inherit + PERF_SAMPLE_READ will be per-thread. Any event
* that is part of such a group that is inherit but not PERF_SAMPLE_READ
* will be read as per-thread. If such an event can also trigger a
* sample (such as with sample_period > 0) then it will not cause
* `read_format` to be included in its PERF_RECORD_SAMPLE, and
* therefore will not expose the per-thread group members as global.
*/
union {
/*
* Holds total ID period value for PERF_SAMPLE_READ processing
* (when period is not per-thread).
*/
u64 period;
/*
* Holds total ID period value for PERF_SAMPLE_READ processing
* (when period is per-thread).
*/
struct hlist_head periods[PERF_SAMPLE_ID__HLIST_SIZE];
};
};
struct perf_evsel {
@ -58,6 +108,10 @@ struct perf_evsel {
u32 ids;
struct perf_evsel *leader;
/* For events where the read_format value is per-thread rather than
* global, stores the per-thread cumulative period */
struct list_head per_stream_periods;
/* parse modifier helper */
int nr_members;
/*
@ -88,4 +142,9 @@ int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter);
int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
void perf_evsel__free_id(struct perf_evsel *evsel);
bool perf_evsel__attr_has_per_thread_sample_period(struct perf_evsel *evsel);
u64 *perf_sample_id__get_period_storage(struct perf_sample_id *sid, u32 tid,
bool per_thread);
#endif /* __LIBPERF_INTERNAL_EVSEL_H */

View File

@ -2,6 +2,7 @@
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <fcntl.h>
#include <string.h>
#include <linux/string.h>
@ -217,8 +218,40 @@ static int wait_or_whine(struct child_process *cmd, bool block)
int check_if_command_finished(struct child_process *cmd)
{
#ifdef __linux__
char filename[FILENAME_MAX + 12];
char status_line[256];
FILE *status_file;
/*
* Check by reading /proc/<pid>/status as calling waitpid causes
* stdout/stderr to be closed and data lost.
*/
sprintf(filename, "/proc/%d/status", cmd->pid);
status_file = fopen(filename, "r");
if (status_file == NULL) {
/* Open failed assume finish_command was called. */
return true;
}
while (fgets(status_line, sizeof(status_line), status_file) != NULL) {
char *p;
if (strncmp(status_line, "State:", 6))
continue;
fclose(status_file);
p = status_line + 6;
while (isspace(*p))
p++;
return *p == 'Z' ? 1 : 0;
}
/* Read failed assume finish_command was called. */
fclose(status_file);
return 1;
#else
wait_or_whine(cmd, /*block=*/false);
return cmd->finished;
#endif
}
int finish_command(struct child_process *cmd)

View File

@ -20,8 +20,8 @@ static __noreturn inline void die(const char *err, ...)
va_start(params, err);
report(" Fatal: ", err, params);
exit(128);
va_end(params);
exit(128);
}
#define zfree(ptr) ({ free(*ptr); *ptr = NULL; })

View File

@ -39,9 +39,9 @@ trace/beauty/generated/
pmu-events/pmu-events.c
pmu-events/jevents
pmu-events/metric_test.log
tests/shell/*.shellcheck_log
tests/shell/coresight/*.shellcheck_log
tests/shell/lib/*.shellcheck_log
pmu-events/empty-pmu-events.log
pmu-events/test-empty-pmu-events.c
*.shellcheck_log
feature/
libapi/
libbpf/

View File

@ -1,6 +1,6 @@
i synthesize instructions events
y synthesize cycles events
b synthesize branches events (branch misses for Arm SPE)
b synthesize branches events
c synthesize branches events (calls only)
r synthesize branches events (returns only)
x synthesize transactions events

View File

@ -187,7 +187,7 @@ groups:
7 llc-access
2 tlb-miss
1K tlb-access
36 branch-miss
36 branch
0 remote-access
900 memory

View File

@ -47,15 +47,15 @@ feature::
bpf / HAVE_LIBBPF_SUPPORT
bpf_skeletons / HAVE_BPF_SKEL
debuginfod / HAVE_DEBUGINFOD_SUPPORT
dwarf / HAVE_DWARF_SUPPORT
dwarf_getlocations / HAVE_DWARF_GETLOCATIONS_SUPPORT
dwarf / HAVE_LIBDW_SUPPORT
dwarf_getlocations / HAVE_LIBDW_SUPPORT
dwarf-unwind / HAVE_DWARF_UNWIND_SUPPORT
auxtrace / HAVE_AUXTRACE_SUPPORT
libaudit / HAVE_LIBAUDIT_SUPPORT
libbfd / HAVE_LIBBFD_SUPPORT
libcapstone / HAVE_LIBCAPSTONE_SUPPORT
libcrypto / HAVE_LIBCRYPTO_SUPPORT
libdw-dwarf-unwind / HAVE_DWARF_SUPPORT
libdw-dwarf-unwind / HAVE_LIBDW_SUPPORT
libelf / HAVE_LIBELF_SUPPORT
libnuma / HAVE_LIBNUMA_SUPPORT
libopencsd / HAVE_CSTRACE_SUPPORT

View File

@ -247,6 +247,19 @@ annotate.*::
These are in control of addresses, jump function, source code
in lines of assembly code from a specific program.
annotate.disassemblers::
Choose the disassembler to use: "objdump", "llvm", "capstone",
if not specified it will first try, if available, the "llvm" one,
then, if it fails, "capstone", and finally the original "objdump"
based one.
Choosing a different one is useful when handling some feature that
is known to be best support at some point by one of the options,
to compare the output when in doubt about some bug, etc.
This can be a list, in order of preference, the first one that works
finishes the process.
annotate.addr2line::
addr2line binary to use for file names and line numbers.

View File

@ -8,7 +8,7 @@ perf-list - List all symbolic event types
SYNOPSIS
--------
[verse]
'perf list' [--no-desc] [--long-desc]
'perf list' [<options>]
[hw|sw|cache|tracepoint|pmu|sdt|metric|metricgroup|event_glob]
DESCRIPTION
@ -243,6 +243,21 @@ For accessing trace point events perf needs to have read access to
/sys/kernel/tracing, even when perf_event_paranoid is in a relaxed
setting.
TOOL/HWMON EVENTS
-----------------
Some events don't have an associated PMU instead reading values
available to software without perf_event_open. As these events don't
support sampling they can only really be read by tools like perf stat.
Tool events provide times and certain system parameters. Examples
include duration_time, user_time, system_time and num_cpus_online.
Hwmon events provide easy access to hwmon sysfs data typically in
/sys/class/hwmon. This information includes temperatures, fan speeds
and energy usage.
TRACING
-------

View File

@ -391,6 +391,14 @@ OPTIONS
This allows to examine the path the program took to each sample.
The data collection must have used -b (or -j) and -g.
Also show with some branch flags that can be:
- Predicted: display the average percentage of predicated branches.
(predicated number / total number)
- Abort: display the number of tsx aborted branches.
- Cycles: cycles in basic block.
- iterations: display the average number of iterations in callchain list.
--addr2line=<path>::
Path to addr2line binary.

View File

@ -221,6 +221,14 @@ OPTIONS for 'perf sched timehist'
priorities are specified with -: 120-129. A combination of both can also be
provided: 0,120-129.
-P::
--pre-migrations::
Show pre-migration wait time. pre-migration wait time is the time spent
by a task waiting on a runqueue but not getting the chance to run there
and is migrated to a different runqueue where it is finally run. This
time between sched_wakeup and migrate_task is the pre-migration wait
time.
OPTIONS for 'perf sched replay'
------------------------------

View File

@ -624,7 +624,7 @@ as perf_trace_context.perf_script_context .
perf_set_itrace_options(context, itrace_options) - set --itrace options if they have not been set already
perf_sample_srcline(context) - returns source_file_name, line_number
perf_sample_srccode(context) - returns source_file_name, line_number, source_line
perf_config_get(config_name) - returns the value of the named config item, or None if unset
Util.py Module
~~~~~~~~~~~~~~

View File

@ -48,3 +48,20 @@ OPTIONS
--dso::
Specify a DSO for the "Symbols" test.
-w::
--workload=::
Run a built-in workload, to list them use '--list-workloads', current ones include:
noploop, thloop, leafloop, sqrtloop, brstack, datasym and landlock.
Used with the shell script regression tests.
Some accept an extra parameter:
seconds: leafloop, noploop, sqrtloop, thloop
nrloops: brstack
The datasym and landlock workloads don't accept any.
--list-workloads::
List the available workloads to use with -w/--workload.

View File

@ -31,7 +31,7 @@ $(call detected_var,SRCARCH)
ifneq ($(NO_SYSCALL_TABLE),1)
NO_SYSCALL_TABLE := 1
ifeq ($(SRCARCH),$(filter $(SRCARCH),x86 powerpc arm64 s390 mips loongarch))
ifeq ($(SRCARCH),$(filter $(SRCARCH),x86 powerpc arm64 s390 mips loongarch riscv))
NO_SYSCALL_TABLE := 0
endif
@ -83,6 +83,10 @@ ifeq ($(ARCH),mips)
LIBUNWIND_LIBS = -lunwind -lunwind-mips
endif
ifeq ($(ARCH),riscv)
CFLAGS += -I$(OUTPUT)arch/riscv/include/generated
endif
# So far there's only x86 and arm libdw unwind support merged in perf.
# Disable it on all other architectures in case libdw unwind
# support is detected in system. Add supported architectures
@ -91,6 +95,10 @@ ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc s390 csky riscv loon
NO_LIBDW_DWARF_UNWIND := 1
endif
ifneq ($(LIBUNWIND),1)
NO_LIBUNWIND := 1
endif
ifeq ($(LIBUNWIND_LIBS),)
NO_LIBUNWIND := 1
endif
@ -162,8 +170,8 @@ ifeq ($(findstring -static,${LDFLAGS}),-static)
# Must put -ldl after -lebl for dependency
DWARFLIBS += -ldl
endif
FEATURE_CHECK_CFLAGS-libdw-dwarf-unwind := $(LIBDW_CFLAGS)
FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) $(DWARFLIBS)
FEATURE_CHECK_CFLAGS-libdw := $(LIBDW_CFLAGS)
FEATURE_CHECK_LDFLAGS-libdw := $(LIBDW_LDFLAGS) $(DWARFLIBS)
# for linking with debug library, run like:
# make DEBUG=1 LIBBABELTRACE_DIR=/opt/libbabeltrace/
@ -203,10 +211,6 @@ FEATURE_CHECK_CFLAGS-bpf = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arc
# include ARCH specific config
-include $(src-perf)/arch/$(SRCARCH)/Makefile
ifdef PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
CFLAGS += -DHAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
endif
include $(srctree)/tools/scripts/utilities.mak
ifeq ($(call get-executable,$(FLEX)),)
@ -426,7 +430,7 @@ ifeq ($(feature-file-handle), 1)
endif
ifdef NO_LIBELF
NO_DWARF := 1
NO_LIBDW := 1
NO_LIBUNWIND := 1
NO_LIBDW_DWARF_UNWIND := 1
NO_LIBBPF := 1
@ -461,28 +465,11 @@ else
endif
endif
else
ifndef NO_LIBDW_DWARF_UNWIND
ifneq ($(feature-libdw-dwarf-unwind),1)
NO_LIBDW_DWARF_UNWIND := 1
$(warning No libdw DWARF unwind found, Please install elfutils-devel/libdw-dev >= 0.158 and/or set LIBDW_DIR)
ifneq ($(feature-libdw), 1)
ifndef NO_LIBDW
$(warning No libdw.h found or old libdw.h found or elfutils is older than 0.157, disables dwarf support. Please install new elfutils-devel/libdw-dev)
NO_LIBDW := 1
endif
endif
ifneq ($(feature-dwarf), 1)
ifndef NO_DWARF
$(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev)
NO_DWARF := 1
endif
else
ifneq ($(feature-dwarf_getlocations), 1)
$(warning Old libdw.h, finding variables at given 'perf probe' point will not work, install elfutils-devel/libdw-dev >= 0.157)
else
CFLAGS += -DHAVE_DWARF_GETLOCATIONS_SUPPORT
endif # dwarf_getlocations
ifneq ($(feature-dwarf_getcfi), 1)
$(warning Old libdw.h, finding variables at given 'perf probe' point will not work, install elfutils-devel/libdw-dev >= 0.142)
else
CFLAGS += -DHAVE_DWARF_CFI_SUPPORT
endif # dwarf_getcfi
endif # Dwarf support
endif # libelf support
endif # NO_LIBELF
@ -493,7 +480,7 @@ ifeq ($(feature-libaio), 1)
endif
endif
ifdef NO_DWARF
ifdef NO_LIBDW
NO_LIBDW_DWARF_UNWIND := 1
endif
@ -571,17 +558,12 @@ ifndef NO_LIBELF
endif
endif
ifndef NO_DWARF
ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
$(warning DWARF register mappings have not been defined for architecture $(SRCARCH), DWARF support disabled)
NO_DWARF := 1
else
CFLAGS += -DHAVE_DWARF_SUPPORT $(LIBDW_CFLAGS)
LDFLAGS += $(LIBDW_LDFLAGS)
EXTLIBS += ${DWARFLIBS}
$(call detected,CONFIG_DWARF)
endif # PERF_HAVE_DWARF_REGS
endif # NO_DWARF
ifndef NO_LIBDW
CFLAGS += -DHAVE_LIBDW_SUPPORT $(LIBDW_CFLAGS)
LDFLAGS += $(LIBDW_LDFLAGS)
EXTLIBS += ${DWARFLIBS}
$(call detected,CONFIG_LIBDW)
endif # NO_LIBDW
ifndef NO_LIBBPF
ifeq ($(feature-bpf), 1)
@ -630,7 +612,7 @@ ifdef PERF_HAVE_JITDUMP
endif
ifeq ($(SRCARCH),powerpc)
ifndef NO_DWARF
ifndef NO_LIBDW
CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX
endif
endif
@ -750,8 +732,6 @@ endif
ifeq ($(dwarf-post-unwind),1)
CFLAGS += -DHAVE_DWARF_UNWIND_SUPPORT
$(call detected,CONFIG_DWARF_UNWIND)
else
NO_DWARF_UNWIND := 1
endif
ifndef NO_LOCAL_LIBUNWIND
@ -1194,7 +1174,7 @@ endif
ifneq ($(NO_LIBTRACEEVENT),1)
$(call feature_check,libtraceevent)
ifeq ($(feature-libtraceevent), 1)
CFLAGS += -DHAVE_LIBTRACEEVENT
CFLAGS += -DHAVE_LIBTRACEEVENT $(shell $(PKG_CONFIG) --cflags libtraceevent)
LDFLAGS += $(shell $(PKG_CONFIG) --libs-only-L libtraceevent)
EXTLIBS += $(shell $(PKG_CONFIG) --libs-only-l libtraceevent)
LIBTRACEEVENT_VERSION := $(shell $(PKG_CONFIG) --modversion libtraceevent).0.0

View File

@ -40,7 +40,7 @@ include ../scripts/utilities.mak
#
# Define EXTRA_PERFLIBS to pass extra libraries to PERFLIBS.
#
# Define NO_DWARF if you do not want debug-info analysis feature at all.
# Define NO_LIBDW if you do not want debug-info analysis feature at all.
#
# Define WERROR=0 to disable treating any warnings as errors.
#
@ -52,7 +52,7 @@ include ../scripts/utilities.mak
#
# Define NO_LIBELF if you do not want libelf dependency (e.g. cross-builds)
#
# Define NO_LIBUNWIND if you do not want libunwind dependency for dwarf
# Define LIBUNWIND if you do not want libunwind dependency for dwarf
# backtrace post unwind.
#
# Define NO_BACKTRACE if you do not want stack backtrace debug feature
@ -1128,12 +1128,11 @@ endif
install-tests: all install-gtk
$(call QUIET_INSTALL, tests) \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
$(INSTALL) tests/attr.py -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
$(INSTALL) tests/pe-file.exe* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
$(INSTALL) tests/attr/* -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell'; \
$(INSTALL) tests/shell/*.sh '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell'; \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/attr'; \
$(INSTALL) tests/shell/attr/* -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/attr'; \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/lib'; \
$(INSTALL) tests/shell/lib/*.sh -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/lib'; \
$(INSTALL) tests/shell/lib/*.py -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/lib'; \

View File

@ -5,5 +5,7 @@ static int arc__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
{
arch->initialized = true;
arch->objdump.comment_char = ';';
arch->e_machine = EM_ARC;
arch->e_flags = 0;
return 0;
}

View File

@ -1,5 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
ifndef NO_DWARF
PERF_HAVE_DWARF_REGS := 1
endif
PERF_HAVE_JITDUMP := 1

View File

@ -53,6 +53,8 @@ static int arm__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
arch->associate_instruction_ops = arm__associate_instruction_ops;
arch->objdump.comment_char = ';';
arch->objdump.skip_functions_char = '+';
arch->e_machine = EM_ARM;
arch->e_flags = 0;
return 0;
out_free_call:

View File

@ -1,7 +1,5 @@
perf-util-y += perf_regs.o
perf-util-$(CONFIG_DWARF) += dwarf-regs.o
perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o

View File

@ -1,61 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Mapping of DWARF debug register numbers into register names.
*
* Copyright (C) 2010 Will Deacon, ARM Ltd.
*/
#include <stddef.h>
#include <linux/stringify.h>
#include <dwarf-regs.h>
struct pt_regs_dwarfnum {
const char *name;
unsigned int dwarfnum;
};
#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num}
#define GPR_DWARFNUM_NAME(num) \
{.name = __stringify(%r##num), .dwarfnum = num}
#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0}
/*
* Reference:
* http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040a/IHI0040A_aadwarf.pdf
*/
static const struct pt_regs_dwarfnum regdwarfnum_table[] = {
GPR_DWARFNUM_NAME(0),
GPR_DWARFNUM_NAME(1),
GPR_DWARFNUM_NAME(2),
GPR_DWARFNUM_NAME(3),
GPR_DWARFNUM_NAME(4),
GPR_DWARFNUM_NAME(5),
GPR_DWARFNUM_NAME(6),
GPR_DWARFNUM_NAME(7),
GPR_DWARFNUM_NAME(8),
GPR_DWARFNUM_NAME(9),
GPR_DWARFNUM_NAME(10),
REG_DWARFNUM_NAME("%fp", 11),
REG_DWARFNUM_NAME("%ip", 12),
REG_DWARFNUM_NAME("%sp", 13),
REG_DWARFNUM_NAME("%lr", 14),
REG_DWARFNUM_NAME("%pc", 15),
REG_DWARFNUM_END,
};
/**
* get_arch_regstr() - lookup register name from it's DWARF register number
* @n: the DWARF register number
*
* get_arch_regstr() returns the name of the register in struct
* regdwarfnum_table from it's DWARF register number. If the register is not
* found in the table, this returns NULL;
*/
const char *get_arch_regstr(unsigned int n)
{
const struct pt_regs_dwarfnum *roff;
for (roff = regdwarfnum_table; roff->name != NULL; roff++)
if (roff->dwarfnum == n)
return roff->name;
return NULL;
}

View File

@ -1,9 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
ifndef NO_DWARF
PERF_HAVE_DWARF_REGS := 1
endif
PERF_HAVE_JITDUMP := 1
PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
HAVE_KVM_STAT_SUPPORT := 1
#

View File

@ -113,6 +113,8 @@ static int arm64__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
arch->associate_instruction_ops = arm64__associate_instruction_ops;
arch->objdump.comment_char = '/';
arch->objdump.skip_functions_char = '+';
arch->e_machine = EM_AARCH64;
arch->e_flags = 0;
return 0;
out_free_call:

View File

@ -4,7 +4,6 @@ perf-util-y += perf_regs.o
perf-util-y += tsc.o
perf-util-y += pmu.o
perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
perf-util-$(CONFIG_DWARF) += dwarf-regs.o
perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o

View File

@ -23,9 +23,12 @@
#include "../../../util/debug.h"
#include "../../../util/auxtrace.h"
#include "../../../util/record.h"
#include "../../../util/header.h"
#include "../../../util/arm-spe.h"
#include <tools/libc_compat.h> // reallocarray
#define ARM_SPE_CPU_MAGIC 0x1010101010101010ULL
#define KiB(x) ((x) * 1024)
#define MiB(x) ((x) * 1024 * 1024)
@ -37,11 +40,84 @@ struct arm_spe_recording {
bool *wrapped;
};
/*
* arm_spe_find_cpus() returns a new cpu map, and the caller should invoke
* perf_cpu_map__put() to release the map after use.
*/
static struct perf_cpu_map *arm_spe_find_cpus(struct evlist *evlist)
{
struct perf_cpu_map *event_cpus = evlist->core.user_requested_cpus;
struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus();
struct perf_cpu_map *intersect_cpus;
/* cpu map is not "any" CPU , we have specific CPUs to work with */
if (!perf_cpu_map__has_any_cpu(event_cpus)) {
intersect_cpus = perf_cpu_map__intersect(event_cpus, online_cpus);
perf_cpu_map__put(online_cpus);
/* Event can be "any" CPU so count all CPUs. */
} else {
intersect_cpus = online_cpus;
}
return intersect_cpus;
}
static size_t
arm_spe_info_priv_size(struct auxtrace_record *itr __maybe_unused,
struct evlist *evlist __maybe_unused)
struct evlist *evlist)
{
return ARM_SPE_AUXTRACE_PRIV_SIZE;
struct perf_cpu_map *cpu_map = arm_spe_find_cpus(evlist);
size_t size;
if (!cpu_map)
return 0;
size = ARM_SPE_AUXTRACE_PRIV_MAX +
ARM_SPE_CPU_PRIV_MAX * perf_cpu_map__nr(cpu_map);
size *= sizeof(u64);
perf_cpu_map__put(cpu_map);
return size;
}
static int arm_spe_save_cpu_header(struct auxtrace_record *itr,
struct perf_cpu cpu, __u64 data[])
{
struct arm_spe_recording *sper =
container_of(itr, struct arm_spe_recording, itr);
struct perf_pmu *pmu = NULL;
char *cpuid = NULL;
u64 val;
/* Read CPU MIDR */
cpuid = get_cpuid_allow_env_override(cpu);
if (!cpuid)
return -ENOMEM;
val = strtol(cpuid, NULL, 16);
data[ARM_SPE_MAGIC] = ARM_SPE_CPU_MAGIC;
data[ARM_SPE_CPU] = cpu.cpu;
data[ARM_SPE_CPU_NR_PARAMS] = ARM_SPE_CPU_PRIV_MAX - ARM_SPE_CPU_MIDR;
data[ARM_SPE_CPU_MIDR] = val;
/* Find the associate Arm SPE PMU for the CPU */
if (perf_cpu_map__has(sper->arm_spe_pmu->cpus, cpu))
pmu = sper->arm_spe_pmu;
if (!pmu) {
/* No Arm SPE PMU is found */
data[ARM_SPE_CPU_PMU_TYPE] = ULLONG_MAX;
data[ARM_SPE_CAP_MIN_IVAL] = 0;
} else {
data[ARM_SPE_CPU_PMU_TYPE] = pmu->type;
if (perf_pmu__scan_file(pmu, "caps/min_interval", "%lu", &val) != 1)
val = 0;
data[ARM_SPE_CAP_MIN_IVAL] = val;
}
free(cpuid);
return ARM_SPE_CPU_PRIV_MAX;
}
static int arm_spe_info_fill(struct auxtrace_record *itr,
@ -49,20 +125,46 @@ static int arm_spe_info_fill(struct auxtrace_record *itr,
struct perf_record_auxtrace_info *auxtrace_info,
size_t priv_size)
{
int i, ret;
size_t offset;
struct arm_spe_recording *sper =
container_of(itr, struct arm_spe_recording, itr);
struct perf_pmu *arm_spe_pmu = sper->arm_spe_pmu;
struct perf_cpu_map *cpu_map;
struct perf_cpu cpu;
__u64 *data;
if (priv_size != ARM_SPE_AUXTRACE_PRIV_SIZE)
if (priv_size != arm_spe_info_priv_size(itr, session->evlist))
return -EINVAL;
if (!session->evlist->core.nr_mmaps)
return -EINVAL;
auxtrace_info->type = PERF_AUXTRACE_ARM_SPE;
auxtrace_info->priv[ARM_SPE_PMU_TYPE] = arm_spe_pmu->type;
cpu_map = arm_spe_find_cpus(session->evlist);
if (!cpu_map)
return -EINVAL;
return 0;
auxtrace_info->type = PERF_AUXTRACE_ARM_SPE;
auxtrace_info->priv[ARM_SPE_HEADER_VERSION] = ARM_SPE_HEADER_CURRENT_VERSION;
auxtrace_info->priv[ARM_SPE_HEADER_SIZE] =
ARM_SPE_AUXTRACE_PRIV_MAX - ARM_SPE_HEADER_VERSION;
auxtrace_info->priv[ARM_SPE_PMU_TYPE_V2] = arm_spe_pmu->type;
auxtrace_info->priv[ARM_SPE_CPUS_NUM] = perf_cpu_map__nr(cpu_map);
offset = ARM_SPE_AUXTRACE_PRIV_MAX;
perf_cpu_map__for_each_cpu(cpu, i, cpu_map) {
assert(offset < priv_size);
data = &auxtrace_info->priv[offset];
ret = arm_spe_save_cpu_header(itr, cpu, data);
if (ret < 0)
goto out;
offset += ret;
}
ret = 0;
out:
perf_cpu_map__put(cpu_map);
return ret;
}
static void
@ -188,9 +290,9 @@ static int arm_spe_recording_options(struct auxtrace_record *itr,
evlist__for_each_entry(evlist, evsel) {
if (evsel__is_aux_event(evsel)) {
if (!strstarts(evsel->pmu_name, ARM_SPE_PMU_NAME)) {
if (!strstarts(evsel->pmu->name, ARM_SPE_PMU_NAME)) {
pr_err("Found unexpected auxtrace event: %s\n",
evsel->pmu_name);
evsel->pmu->name);
return -EINVAL;
}
opts->full_auxtrace = true;

View File

@ -1,92 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Mapping of DWARF debug register numbers into register names.
*
* Copyright (C) 2010 Will Deacon, ARM Ltd.
*/
#include <errno.h>
#include <stddef.h>
#include <string.h>
#include <dwarf-regs.h>
#include <linux/ptrace.h> /* for struct user_pt_regs */
#include <linux/stringify.h>
struct pt_regs_dwarfnum {
const char *name;
unsigned int dwarfnum;
};
#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num}
#define GPR_DWARFNUM_NAME(num) \
{.name = __stringify(%x##num), .dwarfnum = num}
#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0}
#define DWARFNUM2OFFSET(index) \
(index * sizeof((struct user_pt_regs *)0)->regs[0])
/*
* Reference:
* http://infocenter.arm.com/help/topic/com.arm.doc.ihi0057b/IHI0057B_aadwarf64.pdf
*/
static const struct pt_regs_dwarfnum regdwarfnum_table[] = {
GPR_DWARFNUM_NAME(0),
GPR_DWARFNUM_NAME(1),
GPR_DWARFNUM_NAME(2),
GPR_DWARFNUM_NAME(3),
GPR_DWARFNUM_NAME(4),
GPR_DWARFNUM_NAME(5),
GPR_DWARFNUM_NAME(6),
GPR_DWARFNUM_NAME(7),
GPR_DWARFNUM_NAME(8),
GPR_DWARFNUM_NAME(9),
GPR_DWARFNUM_NAME(10),
GPR_DWARFNUM_NAME(11),
GPR_DWARFNUM_NAME(12),
GPR_DWARFNUM_NAME(13),
GPR_DWARFNUM_NAME(14),
GPR_DWARFNUM_NAME(15),
GPR_DWARFNUM_NAME(16),
GPR_DWARFNUM_NAME(17),
GPR_DWARFNUM_NAME(18),
GPR_DWARFNUM_NAME(19),
GPR_DWARFNUM_NAME(20),
GPR_DWARFNUM_NAME(21),
GPR_DWARFNUM_NAME(22),
GPR_DWARFNUM_NAME(23),
GPR_DWARFNUM_NAME(24),
GPR_DWARFNUM_NAME(25),
GPR_DWARFNUM_NAME(26),
GPR_DWARFNUM_NAME(27),
GPR_DWARFNUM_NAME(28),
GPR_DWARFNUM_NAME(29),
REG_DWARFNUM_NAME("%lr", 30),
REG_DWARFNUM_NAME("%sp", 31),
REG_DWARFNUM_END,
};
/**
* get_arch_regstr() - lookup register name from it's DWARF register number
* @n: the DWARF register number
*
* get_arch_regstr() returns the name of the register in struct
* regdwarfnum_table from it's DWARF register number. If the register is not
* found in the table, this returns NULL;
*/
const char *get_arch_regstr(unsigned int n)
{
const struct pt_regs_dwarfnum *roff;
for (roff = regdwarfnum_table; roff->name != NULL; roff++)
if (roff->dwarfnum == n)
return roff->name;
return NULL;
}
int regs_query_register_offset(const char *name)
{
const struct pt_regs_dwarfnum *roff;
for (roff = regdwarfnum_table; roff->name != NULL; roff++)
if (!strcmp(roff->name, name))
return DWARFNUM2OFFSET(roff->dwarfnum);
return -EINVAL;
}

View File

@ -14,73 +14,66 @@
#define MIDR_REVISION_MASK GENMASK(3, 0)
#define MIDR_VARIANT_MASK GENMASK(23, 20)
static int _get_cpuid(char *buf, size_t sz, struct perf_cpu_map *cpus)
static int _get_cpuid(char *buf, size_t sz, struct perf_cpu cpu)
{
char path[PATH_MAX];
FILE *file;
const char *sysfs = sysfs__mountpoint();
struct perf_cpu cpu;
int idx, ret = EINVAL;
assert(cpu.cpu != -1);
if (!sysfs || sz < MIDR_SIZE)
return EINVAL;
perf_cpu_map__for_each_cpu(cpu, idx, cpus) {
char path[PATH_MAX];
FILE *file;
scnprintf(path, PATH_MAX, "%s/devices/system/cpu/cpu%d" MIDR, sysfs, cpu.cpu);
scnprintf(path, PATH_MAX, "%s/devices/system/cpu/cpu%d" MIDR,
sysfs, cpu.cpu);
file = fopen(path, "r");
if (!file) {
pr_debug("fopen failed for file %s\n", path);
continue;
}
if (!fgets(buf, MIDR_SIZE, file)) {
fclose(file);
continue;
}
fclose(file);
/* got midr break loop */
ret = 0;
break;
file = fopen(path, "r");
if (!file) {
pr_debug("fopen failed for file %s\n", path);
return EINVAL;
}
return ret;
if (!fgets(buf, MIDR_SIZE, file)) {
pr_debug("Failed to read file %s\n", path);
fclose(file);
return EINVAL;
}
fclose(file);
return 0;
}
int get_cpuid(char *buf, size_t sz)
int get_cpuid(char *buf, size_t sz, struct perf_cpu cpu)
{
struct perf_cpu_map *cpus = perf_cpu_map__new_online_cpus();
int ret;
struct perf_cpu_map *cpus;
int idx;
if (cpu.cpu != -1)
return _get_cpuid(buf, sz, cpu);
cpus = perf_cpu_map__new_online_cpus();
if (!cpus)
return EINVAL;
ret = _get_cpuid(buf, sz, cpus);
perf_cpu_map__for_each_cpu(cpu, idx, cpus) {
int ret = _get_cpuid(buf, sz, cpu);
perf_cpu_map__put(cpus);
return ret;
if (ret == 0)
return 0;
}
return EINVAL;
}
char *get_cpuid_str(struct perf_pmu *pmu)
char *get_cpuid_str(struct perf_cpu cpu)
{
char *buf = NULL;
char *buf = malloc(MIDR_SIZE);
int res;
if (!pmu || !pmu->cpus)
return NULL;
buf = malloc(MIDR_SIZE);
if (!buf)
return NULL;
/* read midr from list of cpus mapped to this pmu */
res = _get_cpuid(buf, MIDR_SIZE, pmu->cpus);
res = get_cpuid(buf, MIDR_SIZE, cpu);
if (res) {
pr_err("failed to get cpuid string for PMU %s\n", pmu->name);
pr_err("failed to get cpuid string for CPU %d\n", cpu.cpu);
free(buf);
buf = NULL;
}

View File

@ -1,30 +1,11 @@
// SPDX-License-Identifier: GPL-2.0
#include <internal/cpumap.h>
#include "../../../util/cpumap.h"
#include "../../../util/header.h"
#include "../../../util/pmu.h"
#include "../../../util/pmus.h"
#include "../../../util/tool_pmu.h"
#include <api/fs/fs.h>
#include <math.h>
const struct pmu_metrics_table *pmu_metrics_table__find(void)
{
struct perf_pmu *pmu;
/* Metrics aren't currently supported on heterogeneous Arm systems */
if (perf_pmus__num_core_pmus() > 1)
return NULL;
/* Doesn't matter which one here because they'll all be the same */
pmu = perf_pmus__find_core_pmu();
if (pmu)
return perf_pmu__find_metrics_table(pmu);
return NULL;
}
double perf_pmu__cpu_slots_per_cycle(void)
u64 tool_pmu__cpu_slots_per_cycle(void)
{
char path[PATH_MAX];
unsigned long long slots = 0;
@ -41,5 +22,5 @@ double perf_pmu__cpu_slots_per_cycle(void)
filename__read_ull(path, &slots);
}
return slots ? (double)slots : NAN;
return slots;
}

View File

@ -1,4 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
ifndef NO_DWARF
PERF_HAVE_DWARF_REGS := 1
endif

View File

@ -43,6 +43,11 @@ static int csky__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
arch->initialized = true;
arch->objdump.comment_char = '/';
arch->associate_instruction_ops = csky__associate_ins_ops;
arch->e_machine = EM_CSKY;
#if defined(__CSKYABIV2__)
arch->e_flags = EF_CSKY_ABIV2;
#else
arch->e_flags = EF_CSKY_ABIV1;
#endif
return 0;
}

View File

@ -1,4 +1,3 @@
perf-util-y += perf_regs.o
perf-util-$(CONFIG_DWARF) += dwarf-regs.o
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o

View File

@ -1,8 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
ifndef NO_DWARF
PERF_HAVE_DWARF_REGS := 1
endif
PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
PERF_HAVE_JITDUMP := 1
HAVE_KVM_STAT_SUPPORT := 1

View File

@ -131,6 +131,8 @@ int loongarch__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
arch->associate_instruction_ops = loongarch__associate_ins_ops;
arch->initialized = true;
arch->objdump.comment_char = '#';
arch->e_machine = EM_LOONGARCH;
arch->e_flags = 0;
}
return 0;

View File

@ -1,7 +1,6 @@
perf-util-y += header.o
perf-util-y += perf_regs.o
perf-util-$(CONFIG_DWARF) += dwarf-regs.o
perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o

View File

@ -1,44 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* dwarf-regs.c : Mapping of DWARF debug register numbers into register names.
*
* Copyright (C) 2020-2023 Loongson Technology Corporation Limited
*/
#include <stdio.h>
#include <errno.h> /* for EINVAL */
#include <string.h> /* for strcmp */
#include <dwarf-regs.h>
struct pt_regs_dwarfnum {
const char *name;
unsigned int dwarfnum;
};
static struct pt_regs_dwarfnum loongarch_gpr_table[] = {
{"%r0", 0}, {"%r1", 1}, {"%r2", 2}, {"%r3", 3},
{"%r4", 4}, {"%r5", 5}, {"%r6", 6}, {"%r7", 7},
{"%r8", 8}, {"%r9", 9}, {"%r10", 10}, {"%r11", 11},
{"%r12", 12}, {"%r13", 13}, {"%r14", 14}, {"%r15", 15},
{"%r16", 16}, {"%r17", 17}, {"%r18", 18}, {"%r19", 19},
{"%r20", 20}, {"%r21", 21}, {"%r22", 22}, {"%r23", 23},
{"%r24", 24}, {"%r25", 25}, {"%r26", 26}, {"%r27", 27},
{"%r28", 28}, {"%r29", 29}, {"%r30", 30}, {"%r31", 31},
{NULL, 0}
};
const char *get_arch_regstr(unsigned int n)
{
n %= 32;
return loongarch_gpr_table[n].name;
}
int regs_query_register_offset(const char *name)
{
const struct pt_regs_dwarfnum *roff;
for (roff = loongarch_gpr_table; roff->name != NULL; roff++)
if (!strcmp(roff->name, name))
return roff->dwarfnum;
return -EINVAL;
}

View File

@ -70,7 +70,7 @@ static char *_get_cpuid(void)
return cpuid;
}
int get_cpuid(char *buffer, size_t sz)
int get_cpuid(char *buffer, size_t sz, struct perf_cpu cpu __maybe_unused)
{
int ret = 0;
char *cpuid = _get_cpuid();
@ -90,7 +90,7 @@ int get_cpuid(char *buffer, size_t sz)
return ret;
}
char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
char *get_cpuid_str(struct perf_cpu cpu __maybe_unused)
{
return _get_cpuid();
}

View File

@ -1,8 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
ifndef NO_DWARF
PERF_HAVE_DWARF_REGS := 1
endif
# Syscall table generation for perf
out := $(OUTPUT)arch/mips/include/generated/asm
header := $(out)/syscalls_n64.c

View File

@ -40,6 +40,8 @@ int mips__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
arch->associate_instruction_ops = mips__associate_ins_ops;
arch->initialized = true;
arch->objdump.comment_char = '#';
arch->e_machine = EM_MIPS;
arch->e_flags = 0;
}
return 0;

View File

@ -1,3 +1,2 @@
perf-util-y += perf_regs.o
perf-util-$(CONFIG_DWARF) += dwarf-regs.o
perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o

View File

@ -1,38 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* dwarf-regs.c : Mapping of DWARF debug register numbers into register names.
*
* Copyright (C) 2013 Cavium, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <stdio.h>
#include <dwarf-regs.h>
static const char *mips_gpr_names[32] = {
"$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",
"$10", "$11", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "$19",
"$20", "$21", "$22", "$23", "$24", "$25", "$26", "$27", "$28", "$29",
"$30", "$31"
};
const char *get_arch_regstr(unsigned int n)
{
if (n < 32)
return mips_gpr_names[n];
if (n == 64)
return "hi";
if (n == 65)
return "lo";
return NULL;
}

View File

@ -1,10 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
ifndef NO_DWARF
PERF_HAVE_DWARF_REGS := 1
endif
HAVE_KVM_STAT_SUPPORT := 1
PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
PERF_HAVE_JITDUMP := 1
#

View File

@ -255,7 +255,7 @@ static struct ins_ops *check_ppc_insn(struct disasm_line *dl)
* is moved to r31. update_insn_state_powerpc tracks these state
* changes
*/
#ifdef HAVE_DWARF_SUPPORT
#ifdef HAVE_LIBDW_SUPPORT
static void update_insn_state_powerpc(struct type_state *state,
struct data_loc_info *dloc, Dwarf_Die * cu_die __maybe_unused,
struct disasm_line *dl)
@ -300,7 +300,7 @@ static void update_insn_state_powerpc(struct type_state *state,
insn_offset, src->reg1, dst->reg1);
pr_debug_type_name(&tsr->type, tsr->kind);
}
#endif /* HAVE_DWARF_SUPPORT */
#endif /* HAVE_LIBDW_SUPPORT */
static int powerpc__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
{
@ -309,6 +309,8 @@ static int powerpc__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
arch->associate_instruction_ops = powerpc__associate_instruction_ops;
arch->objdump.comment_char = '#';
annotate_opts.show_asm_raw = true;
arch->e_machine = EM_PPC;
arch->e_flags = 0;
}
return 0;

View File

@ -7,8 +7,7 @@ perf-util-y += sym-handling.o
perf-util-y += evsel.o
perf-util-y += event.o
perf-util-$(CONFIG_DWARF) += dwarf-regs.o
perf-util-$(CONFIG_DWARF) += skip-callchain-idx.o
perf-util-$(CONFIG_LIBDW) += skip-callchain-idx.o
perf-util-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o

View File

@ -1,153 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Mapping of DWARF debug register numbers into register names.
*
* Copyright (C) 2010 Ian Munsie, IBM Corporation.
*/
#include <stddef.h>
#include <errno.h>
#include <string.h>
#include <dwarf-regs.h>
#include <linux/ptrace.h>
#include <linux/kernel.h>
#include <linux/stringify.h>
struct pt_regs_dwarfnum {
const char *name;
unsigned int dwarfnum;
unsigned int ptregs_offset;
};
#define REG_DWARFNUM_NAME(r, num) \
{.name = __stringify(%)__stringify(r), .dwarfnum = num, \
.ptregs_offset = offsetof(struct pt_regs, r)}
#define GPR_DWARFNUM_NAME(num) \
{.name = __stringify(%gpr##num), .dwarfnum = num, \
.ptregs_offset = offsetof(struct pt_regs, gpr[num])}
#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0, .ptregs_offset = 0}
/*
* Reference:
* http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html
*/
static const struct pt_regs_dwarfnum regdwarfnum_table[] = {
GPR_DWARFNUM_NAME(0),
GPR_DWARFNUM_NAME(1),
GPR_DWARFNUM_NAME(2),
GPR_DWARFNUM_NAME(3),
GPR_DWARFNUM_NAME(4),
GPR_DWARFNUM_NAME(5),
GPR_DWARFNUM_NAME(6),
GPR_DWARFNUM_NAME(7),
GPR_DWARFNUM_NAME(8),
GPR_DWARFNUM_NAME(9),
GPR_DWARFNUM_NAME(10),
GPR_DWARFNUM_NAME(11),
GPR_DWARFNUM_NAME(12),
GPR_DWARFNUM_NAME(13),
GPR_DWARFNUM_NAME(14),
GPR_DWARFNUM_NAME(15),
GPR_DWARFNUM_NAME(16),
GPR_DWARFNUM_NAME(17),
GPR_DWARFNUM_NAME(18),
GPR_DWARFNUM_NAME(19),
GPR_DWARFNUM_NAME(20),
GPR_DWARFNUM_NAME(21),
GPR_DWARFNUM_NAME(22),
GPR_DWARFNUM_NAME(23),
GPR_DWARFNUM_NAME(24),
GPR_DWARFNUM_NAME(25),
GPR_DWARFNUM_NAME(26),
GPR_DWARFNUM_NAME(27),
GPR_DWARFNUM_NAME(28),
GPR_DWARFNUM_NAME(29),
GPR_DWARFNUM_NAME(30),
GPR_DWARFNUM_NAME(31),
REG_DWARFNUM_NAME(msr, 66),
REG_DWARFNUM_NAME(ctr, 109),
REG_DWARFNUM_NAME(link, 108),
REG_DWARFNUM_NAME(xer, 101),
REG_DWARFNUM_NAME(dar, 119),
REG_DWARFNUM_NAME(dsisr, 118),
REG_DWARFNUM_END,
};
/**
* get_arch_regstr() - lookup register name from it's DWARF register number
* @n: the DWARF register number
*
* get_arch_regstr() returns the name of the register in struct
* regdwarfnum_table from it's DWARF register number. If the register is not
* found in the table, this returns NULL;
*/
const char *get_arch_regstr(unsigned int n)
{
const struct pt_regs_dwarfnum *roff;
for (roff = regdwarfnum_table; roff->name != NULL; roff++)
if (roff->dwarfnum == n)
return roff->name;
return NULL;
}
int regs_query_register_offset(const char *name)
{
const struct pt_regs_dwarfnum *roff;
for (roff = regdwarfnum_table; roff->name != NULL; roff++)
if (!strcmp(roff->name, name))
return roff->ptregs_offset;
return -EINVAL;
}
#define PPC_OP(op) (((op) >> 26) & 0x3F)
#define PPC_RA(a) (((a) >> 16) & 0x1f)
#define PPC_RT(t) (((t) >> 21) & 0x1f)
#define PPC_RB(b) (((b) >> 11) & 0x1f)
#define PPC_D(D) ((D) & 0xfffe)
#define PPC_DS(DS) ((DS) & 0xfffc)
#define OP_LD 58
#define OP_STD 62
static int get_source_reg(u32 raw_insn)
{
return PPC_RA(raw_insn);
}
static int get_target_reg(u32 raw_insn)
{
return PPC_RT(raw_insn);
}
static int get_offset_opcode(u32 raw_insn)
{
int opcode = PPC_OP(raw_insn);
/* DS- form */
if ((opcode == OP_LD) || (opcode == OP_STD))
return PPC_DS(raw_insn);
else
return PPC_D(raw_insn);
}
/*
* Fills the required fields for op_loc depending on if it
* is a source or target.
* D form: ins RT,D(RA) -> src_reg1 = RA, offset = D, dst_reg1 = RT
* DS form: ins RT,DS(RA) -> src_reg1 = RA, offset = DS, dst_reg1 = RT
* X form: ins RT,RA,RB -> src_reg1 = RA, src_reg2 = RB, dst_reg1 = RT
*/
void get_powerpc_regs(u32 raw_insn, int is_source,
struct annotated_op_loc *op_loc)
{
if (is_source)
op_loc->reg1 = get_source_reg(raw_insn);
else
op_loc->reg1 = get_target_reg(raw_insn);
if (op_loc->multi_regs)
op_loc->reg2 = PPC_RB(raw_insn);
/* TODO: Implement offset handling for X Form */
if ((op_loc->mem_ref) && (PPC_OP(raw_insn) != 31))
op_loc->offset = get_offset_opcode(raw_insn);
}

View File

@ -10,9 +10,21 @@
#include "utils_header.h"
#include "metricgroup.h"
#include <api/fs/fs.h>
#include <sys/auxv.h>
static bool is_compat_mode(void)
{
u64 base_platform = getauxval(AT_BASE_PLATFORM);
u64 platform = getauxval(AT_PLATFORM);
if (!strcmp((char *)platform, (char *)base_platform))
return false;
return true;
}
int
get_cpuid(char *buffer, size_t sz)
get_cpuid(char *buffer, size_t sz, struct perf_cpu cpu __maybe_unused)
{
unsigned long pvr;
int nb;
@ -30,11 +42,29 @@ get_cpuid(char *buffer, size_t sz)
}
char *
get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
get_cpuid_str(struct perf_cpu cpu __maybe_unused)
{
char *bufp;
unsigned long pvr;
if (asprintf(&bufp, "0x%.8lx", mfspr(SPRN_PVR)) < 0)
/*
* IBM Power System supports compatible mode. That is
* Nth generation platform can support previous generation
* OS in a mode called compatibile mode. For ex. LPAR can be
* booted in a Power9 mode when the system is a Power10.
*
* In the compatible mode, care must be taken when generating
* PVR value. When read, PVR will be of the AT_BASE_PLATFORM
* To support generic events, return 0x00ffffff as pvr when
* booted in compat mode. Based on this pvr value, json will
* pick events from pmu-events/arch/powerpc/compat
*/
if (!is_compat_mode())
pvr = mfspr(SPRN_PVR);
else
pvr = 0x00ffffff;
if (asprintf(&bufp, "0x%.8lx", pvr) < 0)
bufp = NULL;
return bufp;

View File

@ -1,6 +1,25 @@
ifndef NO_DWARF
PERF_HAVE_DWARF_REGS := 1
endif
PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
# SPDX-License-Identifier: GPL-2.0
PERF_HAVE_JITDUMP := 1
HAVE_KVM_STAT_SUPPORT := 1
#
# Syscall table generation for perf
#
out := $(OUTPUT)arch/riscv/include/generated/asm
header := $(out)/syscalls.c
incpath := $(srctree)/tools
sysdef := $(srctree)/tools/arch/riscv/include/uapi/asm/unistd.h
sysprf := $(srctree)/tools/perf/arch/riscv/entry/syscalls/
systbl := $(sysprf)/mksyscalltbl
# Create output directory if not already present
$(shell [ -d '$(out)' ] || mkdir -p '$(out)')
$(header): $(sysdef) $(systbl)
$(Q)$(SHELL) '$(systbl)' '$(CC)' '$(HOSTCC)' $(incpath) $(sysdef) > $@
clean::
$(call QUIET_CLEAN, riscv) $(RM) $(header)
archheaders: $(header)

View File

@ -0,0 +1,47 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
#
# Generate system call table for perf. Derived from
# powerpc script.
#
# Copyright IBM Corp. 2017
# Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
# Changed by: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
# Changed by: Kim Phillips <kim.phillips@arm.com>
# Changed by: Björn Töpel <bjorn@rivosinc.com>
gcc=$1
hostcc=$2
incpath=$3
input=$4
if ! test -r $input; then
echo "Could not read input file" >&2
exit 1
fi
create_sc_table()
{
local sc nr max_nr
while read sc nr; do
printf "%s\n" " [$nr] = \"$sc\","
max_nr=$nr
done
echo "#define SYSCALLTBL_RISCV_MAX_ID $max_nr"
}
create_table()
{
echo "#include \"$input\""
echo "static const char *const syscalltbl_riscv[] = {"
create_sc_table
echo "};"
}
$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

@ -0,0 +1,42 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifdef DEFINE_DWARF_REGSTR_TABLE
/* This is included in perf/util/dwarf-regs.c */
#define REG_DWARFNUM_NAME(reg, idx) [idx] = "%" #reg
static const char * const riscv_regstr_tbl[] = {
REG_DWARFNUM_NAME("%zero", 0),
REG_DWARFNUM_NAME("%ra", 1),
REG_DWARFNUM_NAME("%sp", 2),
REG_DWARFNUM_NAME("%gp", 3),
REG_DWARFNUM_NAME("%tp", 4),
REG_DWARFNUM_NAME("%t0", 5),
REG_DWARFNUM_NAME("%t1", 6),
REG_DWARFNUM_NAME("%t2", 7),
REG_DWARFNUM_NAME("%s0", 8),
REG_DWARFNUM_NAME("%s1", 9),
REG_DWARFNUM_NAME("%a0", 10),
REG_DWARFNUM_NAME("%a1", 11),
REG_DWARFNUM_NAME("%a2", 12),
REG_DWARFNUM_NAME("%a3", 13),
REG_DWARFNUM_NAME("%a4", 14),
REG_DWARFNUM_NAME("%a5", 15),
REG_DWARFNUM_NAME("%a6", 16),
REG_DWARFNUM_NAME("%a7", 17),
REG_DWARFNUM_NAME("%s2", 18),
REG_DWARFNUM_NAME("%s3", 19),
REG_DWARFNUM_NAME("%s4", 20),
REG_DWARFNUM_NAME("%s5", 21),
REG_DWARFNUM_NAME("%s6", 22),
REG_DWARFNUM_NAME("%s7", 23),
REG_DWARFNUM_NAME("%s8", 24),
REG_DWARFNUM_NAME("%s9", 25),
REG_DWARFNUM_NAME("%s10", 26),
REG_DWARFNUM_NAME("%s11", 27),
REG_DWARFNUM_NAME("%t3", 28),
REG_DWARFNUM_NAME("%t4", 29),
REG_DWARFNUM_NAME("%t5", 30),
REG_DWARFNUM_NAME("%t6", 31),
};
#endif

View File

@ -2,5 +2,4 @@ perf-util-y += perf_regs.o
perf-util-y += header.o
perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
perf-util-$(CONFIG_DWARF) += dwarf-regs.o
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o

View File

@ -1,72 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
* Mapping of DWARF debug register numbers into register names.
*/
#include <stddef.h>
#include <errno.h> /* for EINVAL */
#include <string.h> /* for strcmp */
#include <dwarf-regs.h>
struct pt_regs_dwarfnum {
const char *name;
unsigned int dwarfnum;
};
#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num}
#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0}
struct pt_regs_dwarfnum riscv_dwarf_regs_table[] = {
REG_DWARFNUM_NAME("%zero", 0),
REG_DWARFNUM_NAME("%ra", 1),
REG_DWARFNUM_NAME("%sp", 2),
REG_DWARFNUM_NAME("%gp", 3),
REG_DWARFNUM_NAME("%tp", 4),
REG_DWARFNUM_NAME("%t0", 5),
REG_DWARFNUM_NAME("%t1", 6),
REG_DWARFNUM_NAME("%t2", 7),
REG_DWARFNUM_NAME("%s0", 8),
REG_DWARFNUM_NAME("%s1", 9),
REG_DWARFNUM_NAME("%a0", 10),
REG_DWARFNUM_NAME("%a1", 11),
REG_DWARFNUM_NAME("%a2", 12),
REG_DWARFNUM_NAME("%a3", 13),
REG_DWARFNUM_NAME("%a4", 14),
REG_DWARFNUM_NAME("%a5", 15),
REG_DWARFNUM_NAME("%a6", 16),
REG_DWARFNUM_NAME("%a7", 17),
REG_DWARFNUM_NAME("%s2", 18),
REG_DWARFNUM_NAME("%s3", 19),
REG_DWARFNUM_NAME("%s4", 20),
REG_DWARFNUM_NAME("%s5", 21),
REG_DWARFNUM_NAME("%s6", 22),
REG_DWARFNUM_NAME("%s7", 23),
REG_DWARFNUM_NAME("%s8", 24),
REG_DWARFNUM_NAME("%s9", 25),
REG_DWARFNUM_NAME("%s10", 26),
REG_DWARFNUM_NAME("%s11", 27),
REG_DWARFNUM_NAME("%t3", 28),
REG_DWARFNUM_NAME("%t4", 29),
REG_DWARFNUM_NAME("%t5", 30),
REG_DWARFNUM_NAME("%t6", 31),
REG_DWARFNUM_END,
};
#define RISCV_MAX_REGS ((sizeof(riscv_dwarf_regs_table) / \
sizeof(riscv_dwarf_regs_table[0])) - 1)
const char *get_arch_regstr(unsigned int n)
{
return (n < RISCV_MAX_REGS) ? riscv_dwarf_regs_table[n].name : NULL;
}
int regs_query_register_offset(const char *name)
{
const struct pt_regs_dwarfnum *roff;
for (roff = riscv_dwarf_regs_table; roff->name; roff++)
if (!strcmp(roff->name, name))
return roff->dwarfnum;
return -EINVAL;
}

View File

@ -81,7 +81,7 @@ static char *_get_cpuid(void)
return cpuid;
}
int get_cpuid(char *buffer, size_t sz)
int get_cpuid(char *buffer, size_t sz, struct perf_cpu cpu __maybe_unused)
{
char *cpuid = _get_cpuid();
int ret = 0;
@ -98,7 +98,7 @@ int get_cpuid(char *buffer, size_t sz)
}
char *
get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
get_cpuid_str(struct perf_cpu cpu __maybe_unused)
{
return _get_cpuid();
}

View File

@ -28,6 +28,8 @@ int riscv64__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
arch->associate_instruction_ops = riscv64__associate_ins_ops;
arch->initialized = true;
arch->objdump.comment_char = '#';
arch->e_machine = EM_RISCV;
arch->e_flags = 0;
}
return 0;

View File

@ -1,9 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
ifndef NO_DWARF
PERF_HAVE_DWARF_REGS := 1
endif
HAVE_KVM_STAT_SUPPORT := 1
PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
PERF_HAVE_JITDUMP := 1
#

View File

@ -166,6 +166,8 @@ static int s390__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
if (s390__cpuid_parse(arch, cpuid))
err = SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_CPUID_PARSING;
}
arch->e_machine = EM_S390;
arch->e_flags = 0;
}
return err;

View File

@ -2,7 +2,6 @@ perf-util-y += header.o
perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
perf-util-y += perf_regs.o
perf-util-$(CONFIG_DWARF) += dwarf-regs.o
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
perf-util-y += machine.o

View File

@ -1,43 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Mapping of DWARF debug register numbers into register names.
*
* Copyright IBM Corp. 2010, 2017
* Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
*
*/
#include <errno.h>
#include <stddef.h>
#include <stdlib.h>
#include <linux/kernel.h>
#include <asm/ptrace.h>
#include <string.h>
#include <dwarf-regs.h>
#include "dwarf-regs-table.h"
const char *get_arch_regstr(unsigned int n)
{
return (n >= ARRAY_SIZE(s390_dwarf_regs)) ? NULL : s390_dwarf_regs[n];
}
/*
* Convert the register name into an offset to struct pt_regs (kernel).
* This is required by the BPF prologue generator. The BPF
* program is called in the BPF overflow handler in the perf
* core.
*/
int regs_query_register_offset(const char *name)
{
unsigned long gpr;
if (!name || strncmp(name, "%r", 2))
return -EINVAL;
errno = 0;
gpr = strtoul(name + 2, NULL, 10);
if (errno || gpr >= 16)
return -EINVAL;
return offsetof(user_pt_regs, gprs) + 8 * gpr;
}

View File

@ -27,7 +27,7 @@
#define SYSINFO "/proc/sysinfo"
#define SRVLVL "/proc/service_levels"
int get_cpuid(char *buffer, size_t sz)
int get_cpuid(char *buffer, size_t sz, struct perf_cpu cpu __maybe_unused)
{
char *cp, *line = NULL, *line2;
char type[8], model[33], version[8], manufacturer[32], authorization[8];
@ -137,11 +137,11 @@ int get_cpuid(char *buffer, size_t sz)
return (nbytes >= sz) ? ENOBUFS : 0;
}
char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
char *get_cpuid_str(struct perf_cpu cpu)
{
char *buf = malloc(128);
if (buf && get_cpuid(buf, 128))
if (buf && get_cpuid(buf, 128, cpu))
zfree(&buf);
return buf;
}

View File

@ -1 +0,0 @@
perf-util-y += util/

View File

@ -1,4 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
ifndef NO_DWARF
PERF_HAVE_DWARF_REGS := 1
endif

View File

@ -1 +0,0 @@
perf-util-$(CONFIG_DWARF) += dwarf-regs.o

View File

@ -1,41 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Mapping of DWARF debug register numbers into register names.
*
* Copyright (C) 2010 Matt Fleming <matt@console-pimps.org>
*/
#include <stddef.h>
#include <dwarf-regs.h>
/*
* Generic dwarf analysis helpers
*/
#define SH_MAX_REGS 18
const char *sh_regs_table[SH_MAX_REGS] = {
"r0",
"r1",
"r2",
"r3",
"r4",
"r5",
"r6",
"r7",
"r8",
"r9",
"r10",
"r11",
"r12",
"r13",
"r14",
"r15",
"pc",
"pr",
};
/* Return architecture dependent register string (for kprobe-tracer) */
const char *get_arch_regstr(unsigned int n)
{
return (n < SH_MAX_REGS) ? sh_regs_table[n] : NULL;
}

View File

@ -1 +0,0 @@
perf-util-y += util/

View File

@ -1,6 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
ifndef NO_DWARF
PERF_HAVE_DWARF_REGS := 1
endif
PERF_HAVE_JITDUMP := 1

View File

@ -163,6 +163,8 @@ static int sparc__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
arch->initialized = true;
arch->associate_instruction_ops = sparc__associate_instruction_ops;
arch->objdump.comment_char = '#';
arch->e_machine = EM_SPARC;
arch->e_flags = 0;
}
return 0;

View File

@ -1 +0,0 @@
perf-util-$(CONFIG_DWARF) += dwarf-regs.o

View File

@ -1,39 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Mapping of DWARF debug register numbers into register names.
*
* Copyright (C) 2010 David S. Miller <davem@davemloft.net>
*/
#include <stddef.h>
#include <dwarf-regs.h>
#define SPARC_MAX_REGS 96
const char *sparc_regs_table[SPARC_MAX_REGS] = {
"%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7",
"%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7",
"%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7",
"%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7",
"%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
"%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15",
"%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
"%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31",
"%f32", "%f33", "%f34", "%f35", "%f36", "%f37", "%f38", "%f39",
"%f40", "%f41", "%f42", "%f43", "%f44", "%f45", "%f46", "%f47",
"%f48", "%f49", "%f50", "%f51", "%f52", "%f53", "%f54", "%f55",
"%f56", "%f57", "%f58", "%f59", "%f60", "%f61", "%f62", "%f63",
};
/**
* get_arch_regstr() - lookup register name from it's DWARF register number
* @n: the DWARF register number
*
* get_arch_regstr() returns the name of the register in struct
* regdwarfnum_table from it's DWARF register number. If the register is not
* found in the table, this returns NULL;
*/
const char *get_arch_regstr(unsigned int n)
{
return (n < SPARC_MAX_REGS) ? sparc_regs_table[n] : NULL;
}

View File

@ -1,9 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
ifndef NO_DWARF
PERF_HAVE_DWARF_REGS := 1
endif
HAVE_KVM_STAT_SUPPORT := 1
PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
PERF_HAVE_JITDUMP := 1
###

View File

@ -202,12 +202,13 @@ static int x86__annotate_init(struct arch *arch, char *cpuid)
if (x86__cpuid_parse(arch, cpuid))
err = SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_CPUID_PARSING;
}
arch->e_machine = EM_X86_64;
arch->e_flags = 0;
arch->initialized = true;
return err;
}
#ifdef HAVE_DWARF_SUPPORT
#ifdef HAVE_LIBDW_SUPPORT
static void update_insn_state_x86(struct type_state *state,
struct data_loc_info *dloc, Dwarf_Die *cu_die,
struct disasm_line *dl)

View File

@ -1,128 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include "tests/tests.h"
#include "cloexec.h"
#include "debug.h"
#include "evlist.h"
#include "evsel.h"
#include "arch-tests.h"
#include <internal/lib.h> // page_size
#include <signal.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
static pid_t spawn(void)
{
pid_t pid;
pid = fork();
if (pid)
return pid;
while(1)
sleep(5);
return 0;
}
/*
* Create an event group that contains both a sampled hardware
* (cpu-cycles) and software (intel_cqm/llc_occupancy/) event. We then
* wait for the hardware perf counter to overflow and generate a PMI,
* which triggers an event read for both of the events in the group.
*
* Since reading Intel CQM event counters requires sending SMP IPIs, the
* CQM pmu needs to handle the above situation gracefully, and return
* the last read counter value to avoid triggering a WARN_ON_ONCE() in
* smp_call_function_many() caused by sending IPIs from NMI context.
*/
int test__intel_cqm_count_nmi_context(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
{
struct evlist *evlist = NULL;
struct evsel *evsel = NULL;
struct perf_event_attr pe;
int i, fd[2], flag, ret;
size_t mmap_len;
void *event;
pid_t pid;
int err = TEST_FAIL;
flag = perf_event_open_cloexec_flag();
evlist = evlist__new();
if (!evlist) {
pr_debug("evlist__new failed\n");
return TEST_FAIL;
}
ret = parse_event(evlist, "intel_cqm/llc_occupancy/");
if (ret) {
pr_debug("parse_events failed, is \"intel_cqm/llc_occupancy/\" available?\n");
err = TEST_SKIP;
goto out;
}
evsel = evlist__first(evlist);
if (!evsel) {
pr_debug("evlist__first failed\n");
goto out;
}
memset(&pe, 0, sizeof(pe));
pe.size = sizeof(pe);
pe.type = PERF_TYPE_HARDWARE;
pe.config = PERF_COUNT_HW_CPU_CYCLES;
pe.read_format = PERF_FORMAT_GROUP;
pe.sample_period = 128;
pe.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_READ;
pid = spawn();
fd[0] = sys_perf_event_open(&pe, pid, -1, -1, flag);
if (fd[0] < 0) {
pr_debug("failed to open event\n");
goto out;
}
memset(&pe, 0, sizeof(pe));
pe.size = sizeof(pe);
pe.type = evsel->attr.type;
pe.config = evsel->attr.config;
fd[1] = sys_perf_event_open(&pe, pid, -1, fd[0], flag);
if (fd[1] < 0) {
pr_debug("failed to open event\n");
goto out;
}
/*
* Pick a power-of-two number of pages + 1 for the meta-data
* page (struct perf_event_mmap_page). See tools/perf/design.txt.
*/
mmap_len = page_size * 65;
event = mmap(NULL, mmap_len, PROT_READ, MAP_SHARED, fd[0], 0);
if (event == (void *)(-1)) {
pr_debug("failed to mmap %d\n", errno);
goto out;
}
sleep(1);
err = TEST_OK;
munmap(event, mmap_len);
for (i = 0; i < 2; i++)
close(fd[i]);
kill(pid, SIGKILL);
wait(NULL);
out:
evlist__delete(evlist);
return err;
}

View File

@ -375,7 +375,7 @@ static int get_pt_caps(int cpu, struct pt_caps *caps)
return 0;
}
static bool is_hydrid(void)
static bool is_hybrid(void)
{
unsigned int eax, ebx, ecx, edx = 0;
bool result;
@ -441,7 +441,7 @@ int test__intel_pt_hybrid_compat(struct test_suite *test, int subtest)
int ret = TEST_OK;
int cpu;
if (!is_hydrid()) {
if (!is_hybrid()) {
test->test_cases[subtest].skip_reason = "not hybrid";
return TEST_SKIP;
}

View File

@ -10,10 +10,6 @@ perf-util-y += evlist.o
perf-util-y += mem-events.o
perf-util-y += evsel.o
perf-util-y += iostat.o
perf-util-y += env.o
perf-util-$(CONFIG_DWARF) += dwarf-regs.o
perf-util-$(CONFIG_BPF_PROLOGUE) += dwarf-regs.o
perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o

View File

@ -55,11 +55,12 @@ struct auxtrace_record *auxtrace_record__init(struct evlist *evlist,
int *err)
{
char buffer[64];
struct perf_cpu cpu = perf_cpu_map__min(evlist->core.all_cpus);
int ret;
*err = 0;
ret = get_cpuid(buffer, sizeof(buffer));
ret = get_cpuid(buffer, sizeof(buffer), cpu);
if (ret) {
*err = ret;
return NULL;

View File

@ -1,153 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* dwarf-regs.c : Mapping of DWARF debug register numbers into register names.
* Extracted from probe-finder.c
*
* Written by Masami Hiramatsu <mhiramat@redhat.com>
*/
#include <stddef.h>
#include <errno.h> /* for EINVAL */
#include <string.h> /* for strcmp */
#include <linux/ptrace.h> /* for struct pt_regs */
#include <linux/kernel.h> /* for offsetof */
#include <dwarf-regs.h>
/*
* See arch/x86/kernel/ptrace.c.
* Different from it:
*
* - Since struct pt_regs is defined differently for user and kernel,
* but we want to use 'ax, bx' instead of 'rax, rbx' (which is struct
* field name of user's pt_regs), we make REG_OFFSET_NAME to accept
* both string name and reg field name.
*
* - Since accessing x86_32's pt_regs from x86_64 building is difficult
* and vise versa, we simply fill offset with -1, so
* get_arch_regstr() still works but regs_query_register_offset()
* returns error.
* The only inconvenience caused by it now is that we are not allowed
* to generate BPF prologue for a x86_64 kernel if perf is built for
* x86_32. This is really a rare usecase.
*
* - Order is different from kernel's ptrace.c for get_arch_regstr(). Use
* the order defined by dwarf.
*/
struct pt_regs_offset {
const char *name;
int offset;
};
#define REG_OFFSET_END {.name = NULL, .offset = 0}
#ifdef __x86_64__
# define REG_OFFSET_NAME_64(n, r) {.name = n, .offset = offsetof(struct pt_regs, r)}
# define REG_OFFSET_NAME_32(n, r) {.name = n, .offset = -1}
#else
# define REG_OFFSET_NAME_64(n, r) {.name = n, .offset = -1}
# define REG_OFFSET_NAME_32(n, r) {.name = n, .offset = offsetof(struct pt_regs, r)}
#endif
/* TODO: switching by dwarf address size */
#ifndef __x86_64__
static const struct pt_regs_offset x86_32_regoffset_table[] = {
REG_OFFSET_NAME_32("%ax", eax),
REG_OFFSET_NAME_32("%cx", ecx),
REG_OFFSET_NAME_32("%dx", edx),
REG_OFFSET_NAME_32("%bx", ebx),
REG_OFFSET_NAME_32("$stack", esp), /* Stack address instead of %sp */
REG_OFFSET_NAME_32("%bp", ebp),
REG_OFFSET_NAME_32("%si", esi),
REG_OFFSET_NAME_32("%di", edi),
REG_OFFSET_END,
};
#define regoffset_table x86_32_regoffset_table
#else
static const struct pt_regs_offset x86_64_regoffset_table[] = {
REG_OFFSET_NAME_64("%ax", rax),
REG_OFFSET_NAME_64("%dx", rdx),
REG_OFFSET_NAME_64("%cx", rcx),
REG_OFFSET_NAME_64("%bx", rbx),
REG_OFFSET_NAME_64("%si", rsi),
REG_OFFSET_NAME_64("%di", rdi),
REG_OFFSET_NAME_64("%bp", rbp),
REG_OFFSET_NAME_64("%sp", rsp),
REG_OFFSET_NAME_64("%r8", r8),
REG_OFFSET_NAME_64("%r9", r9),
REG_OFFSET_NAME_64("%r10", r10),
REG_OFFSET_NAME_64("%r11", r11),
REG_OFFSET_NAME_64("%r12", r12),
REG_OFFSET_NAME_64("%r13", r13),
REG_OFFSET_NAME_64("%r14", r14),
REG_OFFSET_NAME_64("%r15", r15),
REG_OFFSET_END,
};
#define regoffset_table x86_64_regoffset_table
#endif
/* Minus 1 for the ending REG_OFFSET_END */
#define ARCH_MAX_REGS ((sizeof(regoffset_table) / sizeof(regoffset_table[0])) - 1)
/* Return architecture dependent register string (for kprobe-tracer) */
const char *get_arch_regstr(unsigned int n)
{
return (n < ARCH_MAX_REGS) ? regoffset_table[n].name : NULL;
}
/* Reuse code from arch/x86/kernel/ptrace.c */
/**
* regs_query_register_offset() - query register offset from its name
* @name: the name of a register
*
* regs_query_register_offset() returns the offset of a register in struct
* pt_regs from its name. If the name is invalid, this returns -EINVAL;
*/
int regs_query_register_offset(const char *name)
{
const struct pt_regs_offset *roff;
for (roff = regoffset_table; roff->name != NULL; roff++)
if (!strcmp(roff->name, name))
return roff->offset;
return -EINVAL;
}
struct dwarf_regs_idx {
const char *name;
int idx;
};
static const struct dwarf_regs_idx x86_regidx_table[] = {
{ "rax", 0 }, { "eax", 0 }, { "ax", 0 }, { "al", 0 },
{ "rdx", 1 }, { "edx", 1 }, { "dx", 1 }, { "dl", 1 },
{ "rcx", 2 }, { "ecx", 2 }, { "cx", 2 }, { "cl", 2 },
{ "rbx", 3 }, { "edx", 3 }, { "bx", 3 }, { "bl", 3 },
{ "rsi", 4 }, { "esi", 4 }, { "si", 4 }, { "sil", 4 },
{ "rdi", 5 }, { "edi", 5 }, { "di", 5 }, { "dil", 5 },
{ "rbp", 6 }, { "ebp", 6 }, { "bp", 6 }, { "bpl", 6 },
{ "rsp", 7 }, { "esp", 7 }, { "sp", 7 }, { "spl", 7 },
{ "r8", 8 }, { "r8d", 8 }, { "r8w", 8 }, { "r8b", 8 },
{ "r9", 9 }, { "r9d", 9 }, { "r9w", 9 }, { "r9b", 9 },
{ "r10", 10 }, { "r10d", 10 }, { "r10w", 10 }, { "r10b", 10 },
{ "r11", 11 }, { "r11d", 11 }, { "r11w", 11 }, { "r11b", 11 },
{ "r12", 12 }, { "r12d", 12 }, { "r12w", 12 }, { "r12b", 12 },
{ "r13", 13 }, { "r13d", 13 }, { "r13w", 13 }, { "r13b", 13 },
{ "r14", 14 }, { "r14d", 14 }, { "r14w", 14 }, { "r14b", 14 },
{ "r15", 15 }, { "r15d", 15 }, { "r15w", 15 }, { "r15b", 15 },
{ "rip", DWARF_REG_PC },
};
int get_arch_regnum(const char *name)
{
unsigned int i;
if (*name != '%')
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(x86_regidx_table); i++)
if (!strcmp(x86_regidx_table[i].name, name + 1))
return x86_regidx_table[i].idx;
return -ENOENT;
}

View File

@ -1,19 +0,0 @@
// 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

@ -1,7 +0,0 @@
/* 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,91 +1,86 @@
// 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 <string.h>
#include "../../../util/evlist.h"
#include "../../../util/evsel.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)
{
LIST_HEAD(head);
size_t i = 0;
for (i = 0; i < nr_attrs; i++)
event_attr_init(attrs + i);
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) {
struct evsel *evsel = evsel__new(attrs + i);
if (evsel == NULL)
goto out_delete_partial_list;
list_add_tail(&evsel->core.node, &head);
continue;
}
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;
evsel->core.attr.config |= (__u64)pmu->type << PERF_PMU_TYPE_SHIFT;
cpus = perf_cpu_map__get(pmu->cpus);
evsel->core.cpus = cpus;
evsel->core.own_cpus = perf_cpu_map__get(cpus);
evsel->pmu_name = strdup(pmu->name);
list_add_tail(&evsel->core.node, &head);
}
}
evlist__splice_list_tail(evlist, &head);
return 0;
out_delete_partial_list:
{
struct evsel *evsel, *n;
__evlist__for_each_entry_safe(&head, n, evsel)
evsel__delete(evsel);
}
return -1;
}
int arch_evlist__add_default_attrs(struct evlist *evlist,
struct perf_event_attr *attrs,
size_t nr_attrs)
{
if (!nr_attrs)
return 0;
return ___evlist__add_default_attrs(evlist, attrs, nr_attrs);
}
int arch_evlist__cmp(const struct evsel *lhs, const struct evsel *rhs)
{
/*
* Currently the following topdown events sequence are supported to
* move and regroup correctly.
*
* a. all events in a group
* perf stat -e "{instructions,topdown-retiring,slots}" -C0 sleep 1
* WARNING: events were regrouped to match PMUs
* Performance counter stats for 'CPU(s) 0':
* 15,066,240 slots
* 1,899,760 instructions
* 2,126,998 topdown-retiring
* b. all events not in a group
* perf stat -e "instructions,topdown-retiring,slots" -C0 sleep 1
* WARNING: events were regrouped to match PMUs
* Performance counter stats for 'CPU(s) 0':
* 2,045,561 instructions
* 17,108,370 slots
* 2,281,116 topdown-retiring
* c. slots event in a group but topdown metrics events outside the group
* perf stat -e "{instructions,slots},topdown-retiring" -C0 sleep 1
* WARNING: events were regrouped to match PMUs
* Performance counter stats for 'CPU(s) 0':
* 20,323,878 slots
* 2,634,884 instructions
* 3,028,656 topdown-retiring
* d. slots event and topdown metrics events in two groups
* perf stat -e "{instructions,slots},{topdown-retiring}" -C0 sleep 1
* WARNING: events were regrouped to match PMUs
* Performance counter stats for 'CPU(s) 0':
* 26,319,024 slots
* 2,427,791 instructions
* 2,683,508 topdown-retiring
*
* If slots event and topdown metrics events are not in same group, the
* topdown metrics events must be first event after the slots event group,
* otherwise topdown metrics events can't be regrouped correctly, e.g.
*
* a. perf stat -e "{instructions,slots},cycles,topdown-retiring" -C0 sleep 1
* WARNING: events were regrouped to match PMUs
* Performance counter stats for 'CPU(s) 0':
* 17,923,134 slots
* 2,154,855 instructions
* 3,015,058 cycles
* <not supported> topdown-retiring
*
* If slots event and topdown metrics events are in two groups, the group which
* has topdown metrics events must contain only the topdown metrics event,
* otherwise topdown metrics event can't be regrouped correctly as well, e.g.
*
* a. perf stat -e "{instructions,slots},{topdown-retiring,cycles}" -C0 sleep 1
* WARNING: events were regrouped to match PMUs
* Error:
* The sys_perf_event_open() syscall returned with 22 (Invalid argument) for
* event (topdown-retiring)
*/
if (topdown_sys_has_perf_metrics() &&
(arch_evsel__must_be_in_group(lhs) || arch_evsel__must_be_in_group(rhs))) {
/* Ensure the topdown slots comes first. */
if (strcasestr(lhs->name, "slots") && !strcasestr(lhs->name, "uops_retired.slots"))
if (arch_is_topdown_slots(lhs))
return -1;
if (strcasestr(rhs->name, "slots") && !strcasestr(rhs->name, "uops_retired.slots"))
if (arch_is_topdown_slots(rhs))
return 1;
/* Followed by topdown events. */
if (strcasestr(lhs->name, "topdown") && !strcasestr(rhs->name, "topdown"))
/*
* Move topdown metrics events forward only when topdown metrics
* events are not in same group with previous slots event. If
* topdown metrics events are already in same group with slots
* event, do nothing.
*/
if (arch_is_topdown_metrics(lhs) && !arch_is_topdown_metrics(rhs) &&
lhs->core.leader != rhs->core.leader)
return -1;
if (!strcasestr(lhs->name, "topdown") && strcasestr(rhs->name, "topdown"))
if (!arch_is_topdown_metrics(lhs) && arch_is_topdown_metrics(rhs) &&
lhs->core.leader != rhs->core.leader)
return 1;
}

View File

@ -6,6 +6,7 @@
#include "util/pmu.h"
#include "util/pmus.h"
#include "linux/string.h"
#include "topdown.h"
#include "evsel.h"
#include "util/debug.h"
#include "env.h"
@ -21,7 +22,8 @@ void arch_evsel__set_sample_weight(struct evsel *evsel)
/* Check whether the evsel's PMU supports the perf metrics */
bool evsel__sys_has_perf_metrics(const struct evsel *evsel)
{
const char *pmu_name = evsel->pmu_name ? evsel->pmu_name : "cpu";
struct perf_pmu *pmu;
u32 type = evsel->core.attr.type;
/*
* The PERF_TYPE_RAW type is the core PMU type, e.g., "cpu" PMU
@ -31,11 +33,31 @@ bool evsel__sys_has_perf_metrics(const struct evsel *evsel)
* Checking both the PERF_TYPE_RAW type and the slots event
* should be good enough to detect the perf metrics feature.
*/
if ((evsel->core.attr.type == PERF_TYPE_RAW) &&
perf_pmus__have_event(pmu_name, "slots"))
return true;
again:
switch (type) {
case PERF_TYPE_HARDWARE:
case PERF_TYPE_HW_CACHE:
type = evsel->core.attr.config >> PERF_PMU_TYPE_SHIFT;
if (type)
goto again;
break;
case PERF_TYPE_RAW:
break;
default:
return false;
}
return false;
pmu = evsel->pmu;
if (pmu && perf_pmu__is_fake(pmu))
pmu = NULL;
if (!pmu) {
while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
if (pmu->type == PERF_TYPE_RAW)
break;
}
}
return pmu && perf_pmu__have_event(pmu, "slots");
}
bool arch_evsel__must_be_in_group(const struct evsel *evsel)
@ -44,7 +66,7 @@ bool arch_evsel__must_be_in_group(const struct evsel *evsel)
strcasestr(evsel->name, "uops_retired.slots"))
return false;
return strcasestr(evsel->name, "topdown") || strcasestr(evsel->name, "slots");
return arch_is_topdown_metrics(evsel) || arch_is_topdown_slots(evsel);
}
int arch_evsel__hw_name(struct evsel *evsel, char *bf, size_t size)
@ -63,7 +85,7 @@ int arch_evsel__hw_name(struct evsel *evsel, char *bf, size_t size)
return scnprintf(bf, size, "%s", event_name);
return scnprintf(bf, size, "%s/%s/",
evsel->pmu_name ? evsel->pmu_name : "cpu",
evsel->pmu ? evsel->pmu->name : "cpu",
event_name);
}
@ -108,7 +130,7 @@ int arch_evsel__open_strerror(struct evsel *evsel, char *msg, size_t size)
return 0;
if (!evsel->core.attr.precise_ip &&
!(evsel->pmu_name && !strncmp(evsel->pmu_name, "ibs", 3)))
!(evsel->pmu && !strncmp(evsel->pmu->name, "ibs", 3)))
return 0;
/* More verbose IBS errors. */

View File

@ -58,13 +58,12 @@ __get_cpuid(char *buffer, size_t sz, const char *fmt)
}
int
get_cpuid(char *buffer, size_t sz)
get_cpuid(char *buffer, size_t sz, struct perf_cpu cpu __maybe_unused)
{
return __get_cpuid(buffer, sz, "%s,%u,%u,%u$");
}
char *
get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
char *get_cpuid_str(struct perf_cpu cpu __maybe_unused)
{
char *buf = malloc(128);

View File

@ -75,7 +75,8 @@ static int intel_pt_parse_terms_with_default(const struct perf_pmu *pmu,
goto out_free;
attr.config = *config;
err = perf_pmu__config_terms(pmu, &attr, &terms, /*zero=*/true, /*err=*/NULL);
err = perf_pmu__config_terms(pmu, &attr, &terms, /*zero=*/true, /*apply_hardcoded=*/false,
/*err=*/NULL);
if (err)
goto out_free;

View File

@ -444,7 +444,7 @@ void iostat_print_metric(struct perf_stat_config *config, struct evsel *evsel,
iostat_value = (count->val - prev_count_val) /
((double) count->run / count->ena);
}
out->print_metric(config, out->ctx, NULL, "%8.0f", iostat_metric,
out->print_metric(config, out->ctx, METRIC_THRESHOLD_UNKNOWN, "%8.0f", iostat_metric,
iostat_value / (256 * 1024));
}

View File

@ -16,7 +16,7 @@
#include "../../../util/fncache.h"
#include "../../../util/pmus.h"
#include "mem-events.h"
#include "env.h"
#include "util/env.h"
void perf_pmu__arch_init(struct perf_pmu *pmu __maybe_unused)
{

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include "api/fs/fs.h"
#include "util/evsel.h"
#include "util/evlist.h"
#include "util/pmu.h"
#include "util/pmus.h"
#include "util/topdown.h"
@ -32,6 +33,31 @@ bool topdown_sys_has_perf_metrics(void)
}
#define TOPDOWN_SLOTS 0x0400
bool arch_is_topdown_slots(const struct evsel *evsel)
{
if (evsel->core.attr.config == TOPDOWN_SLOTS)
return true;
return false;
}
bool arch_is_topdown_metrics(const struct evsel *evsel)
{
int config = evsel->core.attr.config;
const char *name_from_config;
struct perf_pmu *pmu;
/* All topdown events have an event code of 0. */
if ((config & 0xFF) != 0)
return false;
pmu = evsel__find_pmu(evsel);
if (!pmu || !pmu->is_core)
return false;
name_from_config = perf_pmu__name_from_config(pmu, config);
return name_from_config && strcasestr(name_from_config, "topdown");
}
/*
* Check whether a topdown group supports sample-read.
@ -41,11 +67,24 @@ bool topdown_sys_has_perf_metrics(void)
*/
bool arch_topdown_sample_read(struct evsel *leader)
{
struct evsel *evsel;
if (!evsel__sys_has_perf_metrics(leader))
return false;
if (leader->core.attr.config == TOPDOWN_SLOTS)
return true;
if (!arch_is_topdown_slots(leader))
return false;
/*
* If slots event as leader event but no topdown metric events
* in group, slots event should still sample as leader.
*/
evlist__for_each_entry(leader->evlist, evsel) {
if (evsel->core.leader != leader->core.leader)
return false;
if (evsel != leader && arch_is_topdown_metrics(evsel))
return true;
}
return false;
}

View File

@ -3,5 +3,7 @@
#define _TOPDOWN_H 1
bool topdown_sys_has_perf_metrics(void);
bool arch_is_topdown_slots(const struct evsel *evsel);
bool arch_is_topdown_metrics(const struct evsel *evsel);
#endif

View File

@ -24,9 +24,9 @@ u64 rdtsc(void)
* ...
* will return 3000000000.
*/
static double cpuinfo_tsc_freq(void)
static u64 cpuinfo_tsc_freq(void)
{
double result = 0;
u64 result = 0;
FILE *cpuinfo;
char *line = NULL;
size_t len = 0;
@ -34,20 +34,22 @@ static double cpuinfo_tsc_freq(void)
cpuinfo = fopen("/proc/cpuinfo", "r");
if (!cpuinfo) {
pr_err("Failed to read /proc/cpuinfo for TSC frequency\n");
return NAN;
return 0;
}
while (getline(&line, &len, cpuinfo) > 0) {
if (!strncmp(line, "model name", 10)) {
char *pos = strstr(line + 11, " @ ");
double float_result;
if (pos && sscanf(pos, " @ %lfGHz", &result) == 1) {
result *= 1000000000;
if (pos && sscanf(pos, " @ %lfGHz", &float_result) == 1) {
float_result *= 1000000000;
result = (u64)float_result;
goto out;
}
}
}
out:
if (fpclassify(result) == FP_ZERO)
if (result == 0)
pr_err("Failed to find TSC frequency in /proc/cpuinfo\n");
free(line);
@ -55,7 +57,7 @@ static double cpuinfo_tsc_freq(void)
return result;
}
double arch_get_tsc_freq(void)
u64 arch_get_tsc_freq(void)
{
unsigned int a, b, c, d, lvl;
static bool cached;
@ -86,6 +88,6 @@ double arch_get_tsc_freq(void)
return tsc;
}
tsc = (double)c * (double)b / (double)a;
tsc = (u64)c * (u64)b / (u64)a;
return tsc;
}

View File

@ -1 +0,0 @@
perf-util-y += util/

View File

@ -1,4 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
ifndef NO_DWARF
PERF_HAVE_DWARF_REGS := 1
endif

View File

@ -1 +0,0 @@
perf-$(CONFIG_DWARF) += dwarf-regs.o

View File

@ -1,21 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Mapping of DWARF debug register numbers into register names.
*
* Copyright (c) 2015 Cadence Design Systems Inc.
*/
#include <stddef.h>
#include <dwarf-regs.h>
#define XTENSA_MAX_REGS 16
const char *xtensa_regs_table[XTENSA_MAX_REGS] = {
"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
"a8", "a9", "a10", "a11", "a12", "a13", "a14", "a15",
};
const char *get_arch_regstr(unsigned int n)
{
return n < XTENSA_MAX_REGS ? xtensa_regs_table[n] : NULL;
}

View File

@ -27,6 +27,7 @@
#include <sys/resource.h>
#include <sys/wait.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <linux/kernel.h>
#include <linux/time64.h>
@ -35,6 +36,7 @@
#include "../util/header.h"
#include "../util/mutex.h"
#include <api/fs/fs.h>
#include <numa.h>
#include <numaif.h>
@ -533,6 +535,57 @@ static int parse_cpu_list(const char *arg)
return 0;
}
/*
* Check whether a CPU is online
*
* Returns:
* 1 -> if CPU is online
* 0 -> if CPU is offline
* -1 -> error case
*/
static int is_cpu_online(unsigned int cpu)
{
char *str;
size_t strlen;
char buf[256];
int status = -1;
struct stat statbuf;
snprintf(buf, sizeof(buf),
"/sys/devices/system/cpu/cpu%d", cpu);
if (stat(buf, &statbuf) != 0)
return 0;
/*
* Check if /sys/devices/system/cpu/cpux/online file
* exists. Some cases cpu0 won't have online file since
* it is not expected to be turned off generally.
* In kernels without CONFIG_HOTPLUG_CPU, this
* file won't exist
*/
snprintf(buf, sizeof(buf),
"/sys/devices/system/cpu/cpu%d/online", cpu);
if (stat(buf, &statbuf) != 0)
return 1;
/*
* Read online file using sysfs__read_str.
* If read or open fails, return -1.
* If read succeeds, return value from file
* which gets stored in "str"
*/
snprintf(buf, sizeof(buf),
"devices/system/cpu/cpu%d/online", cpu);
if (sysfs__read_str(buf, &str, &strlen) < 0)
return status;
status = atoi(str);
free(str);
return status;
}
static int parse_setup_cpu_list(void)
{
struct thread_data *td;

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