Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf tool_pmu: Factor tool events into their own PMU

Rather than treat tool events as a special kind of event, create a
tool only PMU where the events/aliases match the existing
duration_time, user_time and system_time events. Remove special
parsing and printing support for the tool events, but add function
calls for when PMU functions are called on a tool_pmu.

Move the tool PMU code in evsel into tool_pmu.c to better encapsulate
the tool event behavior in that file.

Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/r/20241002032016.333748-5-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

authored by

Ian Rogers and committed by
Namhyung Kim
240505b2 d2f3ecb0

+530 -392
+11 -2
tools/perf/builtin-list.c
··· 19 19 #include "util/string2.h" 20 20 #include "util/strlist.h" 21 21 #include "util/strbuf.h" 22 + #include "util/tool_pmu.h" 22 23 #include <subcmd/pager.h> 23 24 #include <subcmd/parse-options.h> 24 25 #include <linux/zalloc.h> ··· 615 614 event_symbols_hw, PERF_COUNT_HW_MAX); 616 615 else if (strcmp(argv[i], "sw") == 0 || 617 616 strcmp(argv[i], "software") == 0) { 617 + char *old_pmu_glob = default_ps.pmu_glob; 618 + 618 619 print_symbol_events(&print_cb, ps, PERF_TYPE_SOFTWARE, 619 620 event_symbols_sw, PERF_COUNT_SW_MAX); 620 - print_tool_events(&print_cb, ps); 621 + default_ps.pmu_glob = strdup("tool"); 622 + if (!default_ps.pmu_glob) { 623 + ret = -1; 624 + goto out; 625 + } 626 + perf_pmus__print_pmu_events(&print_cb, ps); 627 + zfree(&default_ps.pmu_glob); 628 + default_ps.pmu_glob = old_pmu_glob; 621 629 } else if (strcmp(argv[i], "cache") == 0 || 622 630 strcmp(argv[i], "hwcache") == 0) 623 631 print_hwcache_events(&print_cb, ps); ··· 674 664 event_symbols_hw, PERF_COUNT_HW_MAX); 675 665 print_symbol_events(&print_cb, ps, PERF_TYPE_SOFTWARE, 676 666 event_symbols_sw, PERF_COUNT_SW_MAX); 677 - print_tool_events(&print_cb, ps); 678 667 print_hwcache_events(&print_cb, ps); 679 668 perf_pmus__print_pmu_events(&print_cb, ps); 680 669 print_tracepoint_events(&print_cb, ps);
+1
tools/perf/builtin-stat.c
··· 46 46 #include "util/parse-events.h" 47 47 #include "util/pmus.h" 48 48 #include "util/pmu.h" 49 + #include "util/tool_pmu.h" 49 50 #include "util/event.h" 50 51 #include "util/evlist.h" 51 52 #include "util/evsel.h"
+1
tools/perf/util/Build
··· 83 83 perf-util-y += pmus.o 84 84 perf-util-y += pmu-flex.o 85 85 perf-util-y += pmu-bison.o 86 + perf-util-y += tool_pmu.o 86 87 perf-util-y += svghelper.o 87 88 perf-util-$(CONFIG_LIBTRACEEVENT) += trace-event-info.o 88 89 perf-util-y += trace-event-scripting.o
+17 -255
tools/perf/util/evsel.c
··· 10 10 #include <errno.h> 11 11 #include <inttypes.h> 12 12 #include <linux/bitops.h> 13 - #include <api/io.h> 14 13 #include <api/fs/fs.h> 15 14 #include <api/fs/tracing_path.h> 16 15 #include <linux/hw_breakpoint.h> ··· 50 51 #include "off_cpu.h" 51 52 #include "pmu.h" 52 53 #include "pmus.h" 54 + #include "tool_pmu.h" 53 55 #include "rlimit.h" 54 56 #include "../perf-sys.h" 55 57 #include "util/parse-branch-options.h" ··· 70 70 struct perf_missing_features perf_missing_features; 71 71 72 72 static clockid_t clockid; 73 - 74 - static const char *const perf_tool_event__tool_names[PERF_TOOL_MAX] = { 75 - NULL, 76 - "duration_time", 77 - "user_time", 78 - "system_time", 79 - }; 80 - 81 - const char *perf_tool_event__to_str(enum perf_tool_event ev) 82 - { 83 - if (ev > PERF_TOOL_NONE && ev < PERF_TOOL_MAX) 84 - return perf_tool_event__tool_names[ev]; 85 - 86 - return NULL; 87 - } 88 - 89 - enum perf_tool_event perf_tool_event__from_str(const char *str) 90 - { 91 - int i; 92 - 93 - perf_tool_event__for_each_event(i) { 94 - if (!strcmp(str, perf_tool_event__tool_names[i])) 95 - return i; 96 - } 97 - return PERF_TOOL_NONE; 98 - } 99 - 100 73 101 74 static int evsel__no_extra_init(struct evsel *evsel __maybe_unused) 102 75 { ··· 389 416 evsel->core.leader = orig->core.leader; 390 417 391 418 evsel->max_events = orig->max_events; 392 - evsel->tool_event = orig->tool_event; 393 419 free((char *)evsel->unit); 394 420 evsel->unit = strdup(orig->unit); 395 421 if (evsel->unit == NULL) ··· 586 614 return r + evsel__add_modifiers(evsel, bf + r, size - r); 587 615 } 588 616 589 - static int evsel__tool_name(enum perf_tool_event ev, char *bf, size_t size) 590 - { 591 - return scnprintf(bf, size, "%s", perf_tool_event__to_str(ev)); 592 - } 593 - 594 617 static int __evsel__bp_name(char *bf, size_t size, u64 addr, u64 type) 595 618 { 596 619 int r; ··· 736 769 break; 737 770 738 771 case PERF_TYPE_SOFTWARE: 739 - if (evsel__is_tool(evsel)) 740 - evsel__tool_name(evsel__tool_event(evsel), bf, sizeof(bf)); 741 - else 742 - evsel__sw_name(evsel, bf, sizeof(bf)); 772 + evsel__sw_name(evsel, bf, sizeof(bf)); 743 773 break; 744 774 745 775 case PERF_TYPE_TRACEPOINT: ··· 745 781 746 782 case PERF_TYPE_BREAKPOINT: 747 783 evsel__bp_name(evsel, bf, sizeof(bf)); 784 + break; 785 + 786 + case PERF_PMU_TYPE_TOOL: 787 + scnprintf(bf, sizeof(bf), "%s", evsel__tool_pmu_event_name(evsel)); 748 788 break; 749 789 750 790 default: ··· 776 808 return evsel->metric_id; 777 809 778 810 if (evsel__is_tool(evsel)) 779 - return perf_tool_event__to_str(evsel__tool_event(evsel)); 811 + return evsel__tool_pmu_event_name(evsel); 780 812 781 813 return "unknown"; 782 814 } ··· 1657 1689 return evsel__process_group_data(leader, cpu_map_idx, thread, data); 1658 1690 } 1659 1691 1660 - static bool read_until_char(struct io *io, char e) 1661 - { 1662 - int c; 1663 - 1664 - do { 1665 - c = io__get_char(io); 1666 - if (c == -1) 1667 - return false; 1668 - } while (c != e); 1669 - return true; 1670 - } 1671 - 1672 - static int read_stat_field(int fd, struct perf_cpu cpu, int field, __u64 *val) 1673 - { 1674 - char buf[256]; 1675 - struct io io; 1676 - int i; 1677 - 1678 - io__init(&io, fd, buf, sizeof(buf)); 1679 - 1680 - /* Skip lines to relevant CPU. */ 1681 - for (i = -1; i < cpu.cpu; i++) { 1682 - if (!read_until_char(&io, '\n')) 1683 - return -EINVAL; 1684 - } 1685 - /* Skip to "cpu". */ 1686 - if (io__get_char(&io) != 'c') return -EINVAL; 1687 - if (io__get_char(&io) != 'p') return -EINVAL; 1688 - if (io__get_char(&io) != 'u') return -EINVAL; 1689 - 1690 - /* Skip N of cpuN. */ 1691 - if (!read_until_char(&io, ' ')) 1692 - return -EINVAL; 1693 - 1694 - i = 1; 1695 - while (true) { 1696 - if (io__get_dec(&io, val) != ' ') 1697 - break; 1698 - if (field == i) 1699 - return 0; 1700 - i++; 1701 - } 1702 - return -EINVAL; 1703 - } 1704 - 1705 - static int read_pid_stat_field(int fd, int field, __u64 *val) 1706 - { 1707 - char buf[256]; 1708 - struct io io; 1709 - int c, i; 1710 - 1711 - io__init(&io, fd, buf, sizeof(buf)); 1712 - if (io__get_dec(&io, val) != ' ') 1713 - return -EINVAL; 1714 - if (field == 1) 1715 - return 0; 1716 - 1717 - /* Skip comm. */ 1718 - if (io__get_char(&io) != '(' || !read_until_char(&io, ')')) 1719 - return -EINVAL; 1720 - if (field == 2) 1721 - return -EINVAL; /* String can't be returned. */ 1722 - 1723 - /* Skip state */ 1724 - if (io__get_char(&io) != ' ' || io__get_char(&io) == -1) 1725 - return -EINVAL; 1726 - if (field == 3) 1727 - return -EINVAL; /* String can't be returned. */ 1728 - 1729 - /* Loop over numeric fields*/ 1730 - if (io__get_char(&io) != ' ') 1731 - return -EINVAL; 1732 - 1733 - i = 4; 1734 - while (true) { 1735 - c = io__get_dec(&io, val); 1736 - if (c == -1) 1737 - return -EINVAL; 1738 - if (c == -2) { 1739 - /* Assume a -ve was read */ 1740 - c = io__get_dec(&io, val); 1741 - *val *= -1; 1742 - } 1743 - if (c != ' ') 1744 - return -EINVAL; 1745 - if (field == i) 1746 - return 0; 1747 - i++; 1748 - } 1749 - return -EINVAL; 1750 - } 1751 - 1752 - static int evsel__read_tool(struct evsel *evsel, int cpu_map_idx, int thread) 1753 - { 1754 - __u64 *start_time, cur_time, delta_start; 1755 - int fd, err = 0; 1756 - struct perf_counts_values *count; 1757 - bool adjust = false; 1758 - 1759 - count = perf_counts(evsel->counts, cpu_map_idx, thread); 1760 - 1761 - switch (evsel__tool_event(evsel)) { 1762 - case PERF_TOOL_DURATION_TIME: 1763 - /* 1764 - * Pretend duration_time is only on the first CPU and thread, or 1765 - * else aggregation will scale duration_time by the number of 1766 - * CPUs/threads. 1767 - */ 1768 - start_time = &evsel->start_time; 1769 - if (cpu_map_idx == 0 && thread == 0) 1770 - cur_time = rdclock(); 1771 - else 1772 - cur_time = *start_time; 1773 - break; 1774 - case PERF_TOOL_USER_TIME: 1775 - case PERF_TOOL_SYSTEM_TIME: { 1776 - bool system = evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME; 1777 - 1778 - start_time = xyarray__entry(evsel->start_times, cpu_map_idx, thread); 1779 - fd = FD(evsel, cpu_map_idx, thread); 1780 - lseek(fd, SEEK_SET, 0); 1781 - if (evsel->pid_stat) { 1782 - /* The event exists solely on 1 CPU. */ 1783 - if (cpu_map_idx == 0) 1784 - err = read_pid_stat_field(fd, system ? 15 : 14, &cur_time); 1785 - else 1786 - cur_time = 0; 1787 - } else { 1788 - /* The event is for all threads. */ 1789 - if (thread == 0) { 1790 - struct perf_cpu cpu = perf_cpu_map__cpu(evsel->core.cpus, 1791 - cpu_map_idx); 1792 - 1793 - err = read_stat_field(fd, cpu, system ? 3 : 1, &cur_time); 1794 - } else { 1795 - cur_time = 0; 1796 - } 1797 - } 1798 - adjust = true; 1799 - break; 1800 - } 1801 - case PERF_TOOL_NONE: 1802 - case PERF_TOOL_MAX: 1803 - default: 1804 - err = -EINVAL; 1805 - } 1806 - if (err) 1807 - return err; 1808 - 1809 - delta_start = cur_time - *start_time; 1810 - if (adjust) { 1811 - __u64 ticks_per_sec = sysconf(_SC_CLK_TCK); 1812 - 1813 - delta_start *= 1000000000 / ticks_per_sec; 1814 - } 1815 - count->val = delta_start; 1816 - count->ena = count->run = delta_start; 1817 - count->lost = 0; 1818 - return 0; 1819 - } 1820 - 1821 1692 bool __evsel__match(const struct evsel *evsel, u32 type, u64 config) 1822 1693 { 1823 1694 ··· 1872 2065 static int __evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus, 1873 2066 struct perf_thread_map *threads) 1874 2067 { 2068 + int ret = 0; 1875 2069 int nthreads = perf_thread_map__nr(threads); 1876 2070 1877 2071 if ((perf_missing_features.write_backward && evsel->core.attr.write_backward) || ··· 1903 2095 perf_evsel__alloc_fd(&evsel->core, perf_cpu_map__nr(cpus), nthreads) < 0) 1904 2096 return -ENOMEM; 1905 2097 1906 - if ((evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME || 1907 - evsel__tool_event(evsel) == PERF_TOOL_USER_TIME) && 1908 - !evsel->start_times) { 1909 - evsel->start_times = xyarray__new(perf_cpu_map__nr(cpus), nthreads, sizeof(__u64)); 1910 - if (!evsel->start_times) 1911 - return -ENOMEM; 1912 - } 2098 + if (evsel__is_tool(evsel)) 2099 + ret = evsel__tool_pmu_prepare_open(evsel, cpus, nthreads); 1913 2100 1914 2101 evsel->open_flags = PERF_FLAG_FD_CLOEXEC; 1915 2102 if (evsel->cgrp) 1916 2103 evsel->open_flags |= PERF_FLAG_PID_CGROUP; 1917 2104 1918 - return 0; 2105 + return ret; 1919 2106 } 1920 2107 1921 2108 static void evsel__disable_missing_features(struct evsel *evsel) ··· 2095 2292 int pid = -1, err, old_errno; 2096 2293 enum rlimit_action set_rlimit = NO_CHANGE; 2097 2294 2098 - if (evsel__tool_event(evsel) == PERF_TOOL_DURATION_TIME) { 2099 - if (evsel->core.attr.sample_period) /* no sampling */ 2100 - return -EINVAL; 2101 - evsel->start_time = rdclock(); 2102 - return 0; 2103 - } 2104 - 2105 2295 if (evsel__is_retire_lat(evsel)) 2106 2296 return tpebs_start(evsel->evlist); 2107 2297 ··· 2119 2323 pr_debug3("Opening: %s\n", evsel__name(evsel)); 2120 2324 display_attr(&evsel->core.attr); 2121 2325 2326 + if (evsel__is_tool(evsel)) { 2327 + return evsel__tool_pmu_open(evsel, threads, 2328 + start_cpu_map_idx, 2329 + end_cpu_map_idx); 2330 + } 2331 + 2122 2332 for (idx = start_cpu_map_idx; idx < end_cpu_map_idx; idx++) { 2123 2333 2124 2334 for (thread = 0; thread < nthreads; thread++) { ··· 2135 2333 2136 2334 if (!evsel->cgrp && !evsel->core.system_wide) 2137 2335 pid = perf_thread_map__pid(threads, thread); 2138 - 2139 - if (evsel__tool_event(evsel) == PERF_TOOL_USER_TIME || 2140 - evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME) { 2141 - bool system = evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME; 2142 - __u64 *start_time = NULL; 2143 - 2144 - if (evsel->core.attr.sample_period) { 2145 - /* no sampling */ 2146 - err = -EINVAL; 2147 - goto out_close; 2148 - } 2149 - if (pid > -1) { 2150 - char buf[64]; 2151 - 2152 - snprintf(buf, sizeof(buf), "/proc/%d/stat", pid); 2153 - fd = open(buf, O_RDONLY); 2154 - evsel->pid_stat = true; 2155 - } else { 2156 - fd = open("/proc/stat", O_RDONLY); 2157 - } 2158 - FD(evsel, idx, thread) = fd; 2159 - if (fd < 0) { 2160 - err = -errno; 2161 - goto out_close; 2162 - } 2163 - start_time = xyarray__entry(evsel->start_times, idx, thread); 2164 - if (pid > -1) { 2165 - err = read_pid_stat_field(fd, system ? 15 : 14, 2166 - start_time); 2167 - } else { 2168 - struct perf_cpu cpu; 2169 - 2170 - cpu = perf_cpu_map__cpu(evsel->core.cpus, idx); 2171 - err = read_stat_field(fd, cpu, system ? 3 : 1, 2172 - start_time); 2173 - } 2174 - if (err) 2175 - goto out_close; 2176 - continue; 2177 - } 2178 2336 2179 2337 group_fd = get_group_fd(evsel, idx, thread); 2180 2338
+1 -27
tools/perf/util/evsel.h
··· 11 11 #include <perf/evsel.h> 12 12 #include "symbol_conf.h" 13 13 #include "pmus.h" 14 + #include "pmu.h" 14 15 15 16 struct bpf_object; 16 17 struct cgroup; ··· 23 22 struct hashmap; 24 23 struct bperf_leader_bpf; 25 24 struct bperf_follower_bpf; 26 - struct perf_pmu; 27 25 28 26 typedef int (evsel__sb_cb_t)(union perf_event *event, void *data); 29 - 30 - enum perf_tool_event { 31 - PERF_TOOL_NONE = 0, 32 - PERF_TOOL_DURATION_TIME = 1, 33 - PERF_TOOL_USER_TIME = 2, 34 - PERF_TOOL_SYSTEM_TIME = 3, 35 - 36 - PERF_TOOL_MAX, 37 - }; 38 - 39 - const char *perf_tool_event__to_str(enum perf_tool_event ev); 40 - enum perf_tool_event perf_tool_event__from_str(const char *str); 41 - 42 - #define perf_tool_event__for_each_event(ev) \ 43 - for ((ev) = PERF_TOOL_DURATION_TIME; (ev) < PERF_TOOL_MAX; ev++) 44 27 45 28 /** struct evsel - event selector 46 29 * ··· 67 82 const char *unit; 68 83 struct cgroup *cgrp; 69 84 const char *metric_id; 70 - enum perf_tool_event tool_event; 71 85 /* parse modifier helper */ 72 86 int exclude_GH; 73 87 int sample_read; ··· 305 321 bool evsel__name_is(struct evsel *evsel, const char *name); 306 322 const char *evsel__metric_id(const struct evsel *evsel); 307 323 308 - static inline bool evsel__is_tool(const struct evsel *evsel) 309 - { 310 - return evsel->tool_event != PERF_TOOL_NONE; 311 - } 312 - 313 324 static inline bool evsel__is_retire_lat(const struct evsel *evsel) 314 325 { 315 326 return evsel->retire_lat; 316 - } 317 - 318 - static inline enum perf_tool_event evsel__tool_event(const struct evsel *evsel) 319 - { 320 - return evsel->tool_event; 321 327 } 322 328 323 329 const char *evsel__group_name(struct evsel *evsel);
+1
tools/perf/util/metricgroup.c
··· 14 14 #include "pmus.h" 15 15 #include "print-events.h" 16 16 #include "smt.h" 17 + #include "tool_pmu.h" 17 18 #include "expr.h" 18 19 #include "rblist.h" 19 20 #include <string.h>
-39
tools/perf/util/parse-events.c
··· 301 301 alternate_hw_config) ? 0 : -ENOMEM; 302 302 } 303 303 304 - static int add_event_tool(struct list_head *list, int *idx, 305 - enum perf_tool_event tool_event) 306 - { 307 - struct evsel *evsel; 308 - struct perf_event_attr attr = { 309 - .type = PERF_TYPE_SOFTWARE, 310 - .config = PERF_COUNT_SW_DUMMY, 311 - }; 312 - struct perf_cpu_map *cpu_list = NULL; 313 - 314 - if (tool_event == PERF_TOOL_DURATION_TIME) { 315 - /* Duration time is gathered globally, pretend it is only on CPU0. */ 316 - cpu_list = perf_cpu_map__new("0"); 317 - } 318 - evsel = __add_event(list, idx, &attr, /*init_attr=*/true, /*name=*/NULL, 319 - /*metric_id=*/NULL, /*pmu=*/NULL, 320 - /*config_terms=*/NULL, /*auto_merge_stats=*/false, 321 - cpu_list, 322 - /*alternate_hw_config=*/PERF_COUNT_HW_MAX); 323 - perf_cpu_map__put(cpu_list); 324 - if (!evsel) 325 - return -ENOMEM; 326 - evsel->tool_event = tool_event; 327 - if (tool_event == PERF_TOOL_DURATION_TIME 328 - || tool_event == PERF_TOOL_USER_TIME 329 - || tool_event == PERF_TOOL_SYSTEM_TIME) { 330 - free((char *)evsel->unit); 331 - evsel->unit = strdup("ns"); 332 - } 333 - return 0; 334 - } 335 - 336 304 /** 337 305 * parse_aliases - search names for entries beginning or equalling str ignoring 338 306 * case. If mutliple entries in names match str then the longest ··· 1396 1428 } 1397 1429 return __parse_events_add_numeric(parse_state, list, perf_pmus__find_by_type(type), 1398 1430 type, /*extended_type=*/0, config, head_config); 1399 - } 1400 - 1401 - int parse_events_add_tool(struct parse_events_state *parse_state, 1402 - struct list_head *list, 1403 - int tool_event) 1404 - { 1405 - return add_event_tool(list, &parse_state->idx, tool_event); 1406 1431 } 1407 1432 1408 1433 static bool config_term_percore(struct list_head *config_terms)
-3
tools/perf/util/parse-events.h
··· 229 229 u32 type, u64 config, 230 230 const struct parse_events_terms *head_config, 231 231 bool wildcard); 232 - int parse_events_add_tool(struct parse_events_state *parse_state, 233 - struct list_head *list, 234 - int tool_event); 235 232 int parse_events_add_cache(struct list_head *list, int *idx, const char *name, 236 233 struct parse_events_state *parse_state, 237 234 struct parse_events_terms *parsed_terms);
-11
tools/perf/util/parse-events.l
··· 121 121 return type == PERF_TYPE_HARDWARE ? PE_VALUE_SYM_HW : PE_VALUE_SYM_SW; 122 122 } 123 123 124 - static int tool(yyscan_t scanner, enum perf_tool_event event) 125 - { 126 - YYSTYPE *yylval = parse_events_get_lval(scanner); 127 - 128 - yylval->num = event; 129 - return PE_VALUE_SYM_TOOL; 130 - } 131 - 132 124 static int term(yyscan_t scanner, enum parse_events__term_type type) 133 125 { 134 126 YYSTYPE *yylval = parse_events_get_lval(scanner); ··· 396 404 alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); } 397 405 emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); } 398 406 dummy { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); } 399 - duration_time { return tool(yyscanner, PERF_TOOL_DURATION_TIME); } 400 - user_time { return tool(yyscanner, PERF_TOOL_USER_TIME); } 401 - system_time { return tool(yyscanner, PERF_TOOL_SYSTEM_TIME); } 402 407 bpf-output { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_BPF_OUTPUT); } 403 408 cgroup-switches { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CGROUP_SWITCHES); } 404 409
-16
tools/perf/util/parse-events.y
··· 56 56 57 57 %token PE_START_EVENTS PE_START_TERMS 58 58 %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_TERM 59 - %token PE_VALUE_SYM_TOOL 60 59 %token PE_EVENT_NAME 61 60 %token PE_RAW PE_NAME 62 61 %token PE_MODIFIER_EVENT PE_MODIFIER_BP PE_BP_COLON PE_BP_SLASH ··· 67 68 %type <num> PE_VALUE 68 69 %type <num> PE_VALUE_SYM_HW 69 70 %type <num> PE_VALUE_SYM_SW 70 - %type <num> PE_VALUE_SYM_TOOL 71 71 %type <mod> PE_MODIFIER_EVENT 72 72 %type <term_type> PE_TERM 73 73 %type <num> value_sym ··· 346 348 err = parse_events_add_numeric(_parse_state, list, type, config, /*head_config=*/NULL, wildcard); 347 349 if (err) 348 350 PE_ABORT(err); 349 - $$ = list; 350 - } 351 - | 352 - PE_VALUE_SYM_TOOL sep_slash_slash_dc 353 - { 354 - struct list_head *list; 355 - int err; 356 - 357 - list = alloc_list(); 358 - if (!list) 359 - YYNOMEM; 360 - err = parse_events_add_tool(_parse_state, list, $1); 361 - if (err) 362 - YYNOMEM; 363 351 $$ = list; 364 352 } 365 353
+18 -2
tools/perf/util/pmu.c
··· 19 19 #include "evsel.h" 20 20 #include "pmu.h" 21 21 #include "pmus.h" 22 + #include "tool_pmu.h" 22 23 #include <util/pmu-bison.h> 23 24 #include <util/pmu-flex.h> 24 25 #include "parse-events.h" ··· 1549 1548 { 1550 1549 bool zero = !!pmu->perf_event_attr_init_default; 1551 1550 1551 + if (perf_pmu__is_tool(pmu)) 1552 + return tool_pmu__config_terms(attr, head_terms, err); 1553 + 1552 1554 /* Fake PMU doesn't have proper terms so nothing to configure in attr. */ 1553 1555 if (perf_pmu__is_fake(pmu)) 1554 1556 return 0; ··· 1664 1660 info->scale = 0.0; 1665 1661 info->snapshot = false; 1666 1662 1667 - /* Fake PMU doesn't rewrite terms. */ 1668 - if (perf_pmu__is_fake(pmu)) 1663 + /* Tool/fake PMU doesn't rewrite terms. */ 1664 + if (perf_pmu__is_tool(pmu) || perf_pmu__is_fake(pmu)) 1669 1665 goto out; 1670 1666 1671 1667 list_for_each_entry_safe(term, h, &head_terms->terms, list) { ··· 1835 1831 { 1836 1832 if (!name) 1837 1833 return false; 1834 + if (perf_pmu__is_tool(pmu)) 1835 + return perf_tool_event__from_str(name) != PERF_TOOL_NONE; 1838 1836 if (perf_pmu__find_alias(pmu, name, /*load=*/ true) != NULL) 1839 1837 return true; 1840 1838 if (pmu->cpu_aliases_added || !pmu->events_table) ··· 1847 1841 size_t perf_pmu__num_events(struct perf_pmu *pmu) 1848 1842 { 1849 1843 size_t nr; 1844 + 1845 + if (perf_pmu__is_tool(pmu)) 1846 + return tool_pmu__num_events(); 1850 1847 1851 1848 pmu_aliases_parse(pmu); 1852 1849 nr = pmu->sysfs_aliases + pmu->sys_json_aliases; ··· 1910 1901 }; 1911 1902 int ret = 0; 1912 1903 struct strbuf sb; 1904 + 1905 + if (perf_pmu__is_tool(pmu)) 1906 + return tool_pmu__for_each_event_cb(pmu, state, cb); 1913 1907 1914 1908 strbuf_init(&sb, /*hint=*/ 0); 1915 1909 pmu_aliases_parse(pmu); ··· 2002 1990 case PERF_TYPE_HW_CACHE: return false; 2003 1991 case PERF_TYPE_RAW: return false; 2004 1992 case PERF_TYPE_BREAKPOINT: return true; 1993 + case PERF_PMU_TYPE_TOOL: return true; 2005 1994 default: break; 2006 1995 } 2007 1996 for (size_t i = 0; i < ARRAY_SIZE(known_sw_pmus); i++) { ··· 2329 2316 2330 2317 if (!pmu) 2331 2318 return NULL; 2319 + 2320 + if (perf_pmu__is_tool(pmu)) 2321 + return perf_tool_event__to_str(config); 2332 2322 2333 2323 pmu_aliases_parse(pmu); 2334 2324 pmu_add_cpu_aliases(pmu);
+2
tools/perf/util/pmu.h
··· 37 37 }; 38 38 39 39 enum { 40 + PERF_PMU_TYPE_TOOL = 0xFFFFFFFE, 40 41 PERF_PMU_TYPE_FAKE = 0xFFFFFFFF, 41 42 }; 42 43 ··· 283 282 struct perf_pmu *perf_pmu__create_placeholder_core_pmu(struct list_head *core_pmus); 284 283 void perf_pmu__delete(struct perf_pmu *pmu); 285 284 struct perf_pmu *perf_pmus__find_core_pmu(void); 285 + 286 286 const char *perf_pmu__name_from_config(struct perf_pmu *pmu, u64 config); 287 287 bool perf_pmu__is_fake(const struct perf_pmu *pmu); 288 288
+9
tools/perf/util/pmus.c
··· 15 15 #include "evsel.h" 16 16 #include "pmus.h" 17 17 #include "pmu.h" 18 + #include "tool_pmu.h" 18 19 #include "print-events.h" 19 20 #include "strbuf.h" 20 21 ··· 201 200 int fd; 202 201 DIR *dir; 203 202 struct dirent *dent; 203 + struct perf_pmu *tool_pmu; 204 204 205 205 if (read_sysfs_all_pmus || (core_only && read_sysfs_core_pmus)) 206 206 return; ··· 231 229 pr_err("Failure to set up any core PMUs\n"); 232 230 } 233 231 list_sort(NULL, &core_pmus, pmus_cmp); 232 + if (!core_only) { 233 + tool_pmu = perf_pmus__tool_pmu(); 234 + list_add_tail(&tool_pmu->list, &other_pmus); 235 + } 234 236 list_sort(NULL, &other_pmus, pmus_cmp); 235 237 if (!list_empty(&core_pmus)) { 236 238 read_sysfs_core_pmus = true; ··· 589 583 }; 590 584 int len = pmu_name_len_no_suffix(pmu->name); 591 585 const char *desc = "(see 'man perf-list' or 'man perf-record' on how to encode it)"; 586 + 587 + if (perf_pmu__is_tool(pmu)) 588 + continue; 592 589 593 590 if (!pmu->is_core) 594 591 desc = NULL;
+1 -35
tools/perf/util/print-events.c
··· 29 29 #include "tracepoint.h" 30 30 #include "pfm.h" 31 31 #include "thread_map.h" 32 + #include "tool_pmu.h" 32 33 #include "util.h" 33 34 34 35 #define MAX_NAME_LEN 100 ··· 42 41 "Hardware cache event", 43 42 "Raw event descriptor", 44 43 "Hardware breakpoint", 45 - }; 46 - 47 - static const struct event_symbol event_symbols_tool[PERF_TOOL_MAX] = { 48 - [PERF_TOOL_DURATION_TIME] = { 49 - .symbol = "duration_time", 50 - .alias = "", 51 - }, 52 - [PERF_TOOL_USER_TIME] = { 53 - .symbol = "user_time", 54 - .alias = "", 55 - }, 56 - [PERF_TOOL_SYSTEM_TIME] = { 57 - .symbol = "system_time", 58 - .alias = "", 59 - }, 60 44 }; 61 45 62 46 /* ··· 327 341 return 0; 328 342 } 329 343 330 - void print_tool_events(const struct print_callbacks *print_cb, void *print_state) 331 - { 332 - // Start at 1 because the first enum entry means no tool event. 333 - for (int i = 1; i < PERF_TOOL_MAX; ++i) { 334 - print_cb->print_event(print_state, 335 - "tool", 336 - /*pmu_name=*/NULL, 337 - event_symbols_tool[i].symbol, 338 - event_symbols_tool[i].alias, 339 - /*scale_unit=*/NULL, 340 - /*deprecated=*/false, 341 - "Tool event", 342 - /*desc=*/NULL, 343 - /*long_desc=*/NULL, 344 - /*encoding_desc=*/NULL); 345 - } 346 - } 347 - 348 344 void print_symbol_events(const struct print_callbacks *print_cb, void *print_state, 349 345 unsigned int type, const struct event_symbol *syms, 350 346 unsigned int max) ··· 389 421 event_symbols_hw, PERF_COUNT_HW_MAX); 390 422 print_symbol_events(print_cb, print_state, PERF_TYPE_SOFTWARE, 391 423 event_symbols_sw, PERF_COUNT_SW_MAX); 392 - 393 - print_tool_events(print_cb, print_state); 394 424 395 425 print_hwcache_events(print_cb, print_state); 396 426
-1
tools/perf/util/print-events.h
··· 36 36 void print_symbol_events(const struct print_callbacks *print_cb, void *print_state, 37 37 unsigned int type, const struct event_symbol *syms, 38 38 unsigned int max); 39 - void print_tool_events(const struct print_callbacks *print_cb, void *print_state); 40 39 void print_tracepoint_events(const struct print_callbacks *print_cb, void *print_state); 41 40 bool is_event_supported(u8 type, u64 config); 42 41
+5 -1
tools/perf/util/stat-display.c
··· 22 22 #include "iostat.h" 23 23 #include "pmu.h" 24 24 #include "pmus.h" 25 + #include "tool_pmu.h" 25 26 26 27 #define CNTR_NOT_SUPPORTED "<not supported>" 27 28 #define CNTR_NOT_COUNTED "<not counted>" ··· 983 982 if (config->aggr_mode == AGGR_THREAD && config->system_wide) 984 983 return true; 985 984 986 - /* Tool events have the software PMU but are only gathered on 1. */ 985 + /* 986 + * Many tool events are only gathered on the first index, skip other 987 + * zero values. 988 + */ 987 989 if (evsel__is_tool(counter)) 988 990 return true; 989 991
+1
tools/perf/util/stat-shadow.c
··· 15 15 #include <linux/zalloc.h> 16 16 #include "iostat.h" 17 17 #include "util/hashmap.h" 18 + #include "tool_pmu.h" 18 19 19 20 struct stats walltime_nsecs_stats; 20 21 struct rusage_stats ru_stats;
+411
tools/perf/util/tool_pmu.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + #include "cgroup.h" 3 + #include "counts.h" 4 + #include "evsel.h" 5 + #include "pmu.h" 6 + #include "print-events.h" 7 + #include "time-utils.h" 8 + #include "tool_pmu.h" 9 + #include <api/io.h> 10 + #include <internal/threadmap.h> 11 + #include <perf/threadmap.h> 12 + #include <fcntl.h> 13 + #include <strings.h> 14 + 15 + static const char *const tool_pmu__event_names[PERF_TOOL_MAX] = { 16 + NULL, 17 + "duration_time", 18 + "user_time", 19 + "system_time", 20 + }; 21 + 22 + 23 + const char *perf_tool_event__to_str(enum perf_tool_event ev) 24 + { 25 + if (ev > PERF_TOOL_NONE && ev < PERF_TOOL_MAX) 26 + return tool_pmu__event_names[ev]; 27 + 28 + return NULL; 29 + } 30 + 31 + enum perf_tool_event perf_tool_event__from_str(const char *str) 32 + { 33 + int i; 34 + 35 + perf_tool_event__for_each_event(i) { 36 + if (!strcasecmp(str, tool_pmu__event_names[i])) 37 + return i; 38 + } 39 + return PERF_TOOL_NONE; 40 + } 41 + 42 + static int tool_pmu__config_term(struct perf_event_attr *attr, 43 + struct parse_events_term *term, 44 + struct parse_events_error *err) 45 + { 46 + if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER) { 47 + enum perf_tool_event ev = perf_tool_event__from_str(term->config); 48 + 49 + if (ev == PERF_TOOL_NONE) 50 + goto err_out; 51 + 52 + attr->config = ev; 53 + return 0; 54 + } 55 + err_out: 56 + if (err) { 57 + char *err_str; 58 + 59 + parse_events_error__handle(err, term->err_val, 60 + asprintf(&err_str, 61 + "unexpected tool event term (%s) %s", 62 + parse_events__term_type_str(term->type_term), 63 + term->config) < 0 64 + ? strdup("unexpected tool event term") 65 + : err_str, 66 + NULL); 67 + } 68 + return -EINVAL; 69 + } 70 + 71 + int tool_pmu__config_terms(struct perf_event_attr *attr, 72 + struct parse_events_terms *terms, 73 + struct parse_events_error *err) 74 + { 75 + struct parse_events_term *term; 76 + 77 + list_for_each_entry(term, &terms->terms, list) { 78 + if (tool_pmu__config_term(attr, term, err)) 79 + return -EINVAL; 80 + } 81 + 82 + return 0; 83 + 84 + } 85 + 86 + int tool_pmu__for_each_event_cb(struct perf_pmu *pmu, void *state, pmu_event_callback cb) 87 + { 88 + struct pmu_event_info info = { 89 + .pmu = pmu, 90 + .event_type_desc = "Tool event", 91 + }; 92 + int i; 93 + 94 + perf_tool_event__for_each_event(i) { 95 + int ret; 96 + 97 + info.name = perf_tool_event__to_str(i); 98 + info.alias = NULL; 99 + info.scale_unit = NULL; 100 + info.desc = NULL; 101 + info.long_desc = NULL; 102 + info.encoding_desc = NULL; 103 + info.topic = NULL; 104 + info.pmu_name = pmu->name; 105 + info.deprecated = false; 106 + ret = cb(state, &info); 107 + if (ret) 108 + return ret; 109 + } 110 + return 0; 111 + } 112 + 113 + bool perf_pmu__is_tool(const struct perf_pmu *pmu) 114 + { 115 + return pmu && pmu->type == PERF_PMU_TYPE_TOOL; 116 + } 117 + 118 + bool evsel__is_tool(const struct evsel *evsel) 119 + { 120 + return perf_pmu__is_tool(evsel->pmu); 121 + } 122 + 123 + enum perf_tool_event evsel__tool_event(const struct evsel *evsel) 124 + { 125 + if (!evsel__is_tool(evsel)) 126 + return PERF_TOOL_NONE; 127 + 128 + return (enum perf_tool_event)evsel->core.attr.config; 129 + } 130 + 131 + const char *evsel__tool_pmu_event_name(const struct evsel *evsel) 132 + { 133 + return perf_tool_event__to_str(evsel->core.attr.config); 134 + } 135 + 136 + static bool read_until_char(struct io *io, char e) 137 + { 138 + int c; 139 + 140 + do { 141 + c = io__get_char(io); 142 + if (c == -1) 143 + return false; 144 + } while (c != e); 145 + return true; 146 + } 147 + 148 + static int read_stat_field(int fd, struct perf_cpu cpu, int field, __u64 *val) 149 + { 150 + char buf[256]; 151 + struct io io; 152 + int i; 153 + 154 + io__init(&io, fd, buf, sizeof(buf)); 155 + 156 + /* Skip lines to relevant CPU. */ 157 + for (i = -1; i < cpu.cpu; i++) { 158 + if (!read_until_char(&io, '\n')) 159 + return -EINVAL; 160 + } 161 + /* Skip to "cpu". */ 162 + if (io__get_char(&io) != 'c') return -EINVAL; 163 + if (io__get_char(&io) != 'p') return -EINVAL; 164 + if (io__get_char(&io) != 'u') return -EINVAL; 165 + 166 + /* Skip N of cpuN. */ 167 + if (!read_until_char(&io, ' ')) 168 + return -EINVAL; 169 + 170 + i = 1; 171 + while (true) { 172 + if (io__get_dec(&io, val) != ' ') 173 + break; 174 + if (field == i) 175 + return 0; 176 + i++; 177 + } 178 + return -EINVAL; 179 + } 180 + 181 + static int read_pid_stat_field(int fd, int field, __u64 *val) 182 + { 183 + char buf[256]; 184 + struct io io; 185 + int c, i; 186 + 187 + io__init(&io, fd, buf, sizeof(buf)); 188 + if (io__get_dec(&io, val) != ' ') 189 + return -EINVAL; 190 + if (field == 1) 191 + return 0; 192 + 193 + /* Skip comm. */ 194 + if (io__get_char(&io) != '(' || !read_until_char(&io, ')')) 195 + return -EINVAL; 196 + if (field == 2) 197 + return -EINVAL; /* String can't be returned. */ 198 + 199 + /* Skip state */ 200 + if (io__get_char(&io) != ' ' || io__get_char(&io) == -1) 201 + return -EINVAL; 202 + if (field == 3) 203 + return -EINVAL; /* String can't be returned. */ 204 + 205 + /* Loop over numeric fields*/ 206 + if (io__get_char(&io) != ' ') 207 + return -EINVAL; 208 + 209 + i = 4; 210 + while (true) { 211 + c = io__get_dec(&io, val); 212 + if (c == -1) 213 + return -EINVAL; 214 + if (c == -2) { 215 + /* Assume a -ve was read */ 216 + c = io__get_dec(&io, val); 217 + *val *= -1; 218 + } 219 + if (c != ' ') 220 + return -EINVAL; 221 + if (field == i) 222 + return 0; 223 + i++; 224 + } 225 + return -EINVAL; 226 + } 227 + 228 + int evsel__tool_pmu_prepare_open(struct evsel *evsel, 229 + struct perf_cpu_map *cpus, 230 + int nthreads) 231 + { 232 + if ((evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME || 233 + evsel__tool_event(evsel) == PERF_TOOL_USER_TIME) && 234 + !evsel->start_times) { 235 + evsel->start_times = xyarray__new(perf_cpu_map__nr(cpus), 236 + nthreads, 237 + sizeof(__u64)); 238 + if (!evsel->start_times) 239 + return -ENOMEM; 240 + } 241 + return 0; 242 + } 243 + 244 + #define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y)) 245 + 246 + int evsel__tool_pmu_open(struct evsel *evsel, 247 + struct perf_thread_map *threads, 248 + int start_cpu_map_idx, int end_cpu_map_idx) 249 + { 250 + enum perf_tool_event ev = evsel__tool_event(evsel); 251 + int pid = -1, idx = 0, thread = 0, nthreads, err = 0, old_errno; 252 + 253 + if (ev == PERF_TOOL_DURATION_TIME) { 254 + if (evsel->core.attr.sample_period) /* no sampling */ 255 + return -EINVAL; 256 + evsel->start_time = rdclock(); 257 + return 0; 258 + } 259 + 260 + if (evsel->cgrp) 261 + pid = evsel->cgrp->fd; 262 + 263 + nthreads = perf_thread_map__nr(threads); 264 + for (idx = start_cpu_map_idx; idx < end_cpu_map_idx; idx++) { 265 + for (thread = 0; thread < nthreads; thread++) { 266 + if (thread >= nthreads) 267 + break; 268 + 269 + if (!evsel->cgrp && !evsel->core.system_wide) 270 + pid = perf_thread_map__pid(threads, thread); 271 + 272 + if (ev == PERF_TOOL_USER_TIME || ev == PERF_TOOL_SYSTEM_TIME) { 273 + bool system = ev == PERF_TOOL_SYSTEM_TIME; 274 + __u64 *start_time = NULL; 275 + int fd; 276 + 277 + if (evsel->core.attr.sample_period) { 278 + /* no sampling */ 279 + err = -EINVAL; 280 + goto out_close; 281 + } 282 + if (pid > -1) { 283 + char buf[64]; 284 + 285 + snprintf(buf, sizeof(buf), "/proc/%d/stat", pid); 286 + fd = open(buf, O_RDONLY); 287 + evsel->pid_stat = true; 288 + } else { 289 + fd = open("/proc/stat", O_RDONLY); 290 + } 291 + FD(evsel, idx, thread) = fd; 292 + if (fd < 0) { 293 + err = -errno; 294 + goto out_close; 295 + } 296 + start_time = xyarray__entry(evsel->start_times, idx, thread); 297 + if (pid > -1) { 298 + err = read_pid_stat_field(fd, system ? 15 : 14, 299 + start_time); 300 + } else { 301 + struct perf_cpu cpu; 302 + 303 + cpu = perf_cpu_map__cpu(evsel->core.cpus, idx); 304 + err = read_stat_field(fd, cpu, system ? 3 : 1, 305 + start_time); 306 + } 307 + if (err) 308 + goto out_close; 309 + } 310 + 311 + } 312 + } 313 + return 0; 314 + out_close: 315 + if (err) 316 + threads->err_thread = thread; 317 + 318 + old_errno = errno; 319 + do { 320 + while (--thread >= 0) { 321 + if (FD(evsel, idx, thread) >= 0) 322 + close(FD(evsel, idx, thread)); 323 + FD(evsel, idx, thread) = -1; 324 + } 325 + thread = nthreads; 326 + } while (--idx >= 0); 327 + errno = old_errno; 328 + return err; 329 + } 330 + 331 + int evsel__read_tool(struct evsel *evsel, int cpu_map_idx, int thread) 332 + { 333 + __u64 *start_time, cur_time, delta_start; 334 + int fd, err = 0; 335 + struct perf_counts_values *count; 336 + bool adjust = false; 337 + 338 + count = perf_counts(evsel->counts, cpu_map_idx, thread); 339 + 340 + switch (evsel__tool_event(evsel)) { 341 + case PERF_TOOL_DURATION_TIME: 342 + /* 343 + * Pretend duration_time is only on the first CPU and thread, or 344 + * else aggregation will scale duration_time by the number of 345 + * CPUs/threads. 346 + */ 347 + start_time = &evsel->start_time; 348 + if (cpu_map_idx == 0 && thread == 0) 349 + cur_time = rdclock(); 350 + else 351 + cur_time = *start_time; 352 + break; 353 + case PERF_TOOL_USER_TIME: 354 + case PERF_TOOL_SYSTEM_TIME: { 355 + bool system = evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME; 356 + 357 + start_time = xyarray__entry(evsel->start_times, cpu_map_idx, thread); 358 + fd = FD(evsel, cpu_map_idx, thread); 359 + lseek(fd, SEEK_SET, 0); 360 + if (evsel->pid_stat) { 361 + /* The event exists solely on 1 CPU. */ 362 + if (cpu_map_idx == 0) 363 + err = read_pid_stat_field(fd, system ? 15 : 14, &cur_time); 364 + else 365 + cur_time = 0; 366 + } else { 367 + /* The event is for all threads. */ 368 + if (thread == 0) { 369 + struct perf_cpu cpu = perf_cpu_map__cpu(evsel->core.cpus, 370 + cpu_map_idx); 371 + 372 + err = read_stat_field(fd, cpu, system ? 3 : 1, &cur_time); 373 + } else { 374 + cur_time = 0; 375 + } 376 + } 377 + adjust = true; 378 + break; 379 + } 380 + case PERF_TOOL_NONE: 381 + case PERF_TOOL_MAX: 382 + default: 383 + err = -EINVAL; 384 + } 385 + if (err) 386 + return err; 387 + 388 + delta_start = cur_time - *start_time; 389 + if (adjust) { 390 + __u64 ticks_per_sec = sysconf(_SC_CLK_TCK); 391 + 392 + delta_start *= 1000000000 / ticks_per_sec; 393 + } 394 + count->val = delta_start; 395 + count->ena = count->run = delta_start; 396 + count->lost = 0; 397 + return 0; 398 + } 399 + 400 + struct perf_pmu *perf_pmus__tool_pmu(void) 401 + { 402 + static struct perf_pmu tool = { 403 + .name = "tool", 404 + .type = PERF_PMU_TYPE_TOOL, 405 + .aliases = LIST_HEAD_INIT(tool.aliases), 406 + .caps = LIST_HEAD_INIT(tool.caps), 407 + .format = LIST_HEAD_INIT(tool.format), 408 + }; 409 + 410 + return &tool; 411 + }
+51
tools/perf/util/tool_pmu.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __TOOL_PMU_H 3 + #define __TOOL_PMU_H 4 + 5 + #include "pmu.h" 6 + 7 + struct evsel; 8 + struct perf_thread_map; 9 + struct print_callbacks; 10 + 11 + enum perf_tool_event { 12 + PERF_TOOL_NONE = 0, 13 + PERF_TOOL_DURATION_TIME = 1, 14 + PERF_TOOL_USER_TIME = 2, 15 + PERF_TOOL_SYSTEM_TIME = 3, 16 + 17 + PERF_TOOL_MAX, 18 + }; 19 + 20 + #define perf_tool_event__for_each_event(ev) \ 21 + for ((ev) = PERF_TOOL_DURATION_TIME; (ev) < PERF_TOOL_MAX; ev++) 22 + 23 + static inline size_t tool_pmu__num_events(void) 24 + { 25 + return PERF_TOOL_MAX - 1; 26 + } 27 + 28 + const char *perf_tool_event__to_str(enum perf_tool_event ev); 29 + enum perf_tool_event perf_tool_event__from_str(const char *str); 30 + int tool_pmu__config_terms(struct perf_event_attr *attr, 31 + struct parse_events_terms *terms, 32 + struct parse_events_error *err); 33 + int tool_pmu__for_each_event_cb(struct perf_pmu *pmu, void *state, pmu_event_callback cb); 34 + 35 + bool perf_pmu__is_tool(const struct perf_pmu *pmu); 36 + 37 + 38 + bool evsel__is_tool(const struct evsel *evsel); 39 + enum perf_tool_event evsel__tool_event(const struct evsel *evsel); 40 + const char *evsel__tool_pmu_event_name(const struct evsel *evsel); 41 + int evsel__tool_pmu_prepare_open(struct evsel *evsel, 42 + struct perf_cpu_map *cpus, 43 + int nthreads); 44 + int evsel__tool_pmu_open(struct evsel *evsel, 45 + struct perf_thread_map *threads, 46 + int start_cpu_map_idx, int end_cpu_map_idx); 47 + int evsel__read_tool(struct evsel *evsel, int cpu_map_idx, int thread); 48 + 49 + struct perf_pmu *perf_pmus__tool_pmu(void); 50 + 51 + #endif /* __TOOL_PMU_H */