diff options
| -rw-r--r-- | tools/perf/util/evlist.c | 29 | ||||
| -rw-r--r-- | tools/perf/util/evlist.h | 2 | ||||
| -rw-r--r-- | tools/perf/util/evsel.c | 72 |
3 files changed, 59 insertions, 44 deletions
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index ec78e93085de..6689378ee577 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
| @@ -231,35 +231,6 @@ void perf_evlist__set_leader(struct perf_evlist *evlist) | |||
| 231 | } | 231 | } |
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | void perf_event_attr__set_max_precise_ip(struct perf_event_attr *pattr) | ||
| 235 | { | ||
| 236 | struct perf_event_attr attr = { | ||
| 237 | .type = PERF_TYPE_HARDWARE, | ||
| 238 | .config = PERF_COUNT_HW_CPU_CYCLES, | ||
| 239 | .exclude_kernel = 1, | ||
| 240 | .precise_ip = 3, | ||
| 241 | }; | ||
| 242 | |||
| 243 | event_attr_init(&attr); | ||
| 244 | |||
| 245 | /* | ||
| 246 | * Unnamed union member, not supported as struct member named | ||
| 247 | * initializer in older compilers such as gcc 4.4.7 | ||
| 248 | */ | ||
| 249 | attr.sample_period = 1; | ||
| 250 | |||
| 251 | while (attr.precise_ip != 0) { | ||
| 252 | int fd = sys_perf_event_open(&attr, 0, -1, -1, 0); | ||
| 253 | if (fd != -1) { | ||
| 254 | close(fd); | ||
| 255 | break; | ||
| 256 | } | ||
| 257 | --attr.precise_ip; | ||
| 258 | } | ||
| 259 | |||
| 260 | pattr->precise_ip = attr.precise_ip; | ||
| 261 | } | ||
| 262 | |||
| 263 | int __perf_evlist__add_default(struct perf_evlist *evlist, bool precise) | 234 | int __perf_evlist__add_default(struct perf_evlist *evlist, bool precise) |
| 264 | { | 235 | { |
| 265 | struct perf_evsel *evsel = perf_evsel__new_cycles(precise); | 236 | struct perf_evsel *evsel = perf_evsel__new_cycles(precise); |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index dcb68f34d2cd..6a94785b9100 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
| @@ -315,8 +315,6 @@ void perf_evlist__to_front(struct perf_evlist *evlist, | |||
| 315 | void perf_evlist__set_tracking_event(struct perf_evlist *evlist, | 315 | void perf_evlist__set_tracking_event(struct perf_evlist *evlist, |
| 316 | struct perf_evsel *tracking_evsel); | 316 | struct perf_evsel *tracking_evsel); |
| 317 | 317 | ||
| 318 | void perf_event_attr__set_max_precise_ip(struct perf_event_attr *attr); | ||
| 319 | |||
| 320 | struct perf_evsel * | 318 | struct perf_evsel * |
| 321 | perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, const char *str); | 319 | perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, const char *str); |
| 322 | 320 | ||
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 7835e05f0c0a..66d066f18b5b 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
| @@ -295,7 +295,6 @@ struct perf_evsel *perf_evsel__new_cycles(bool precise) | |||
| 295 | if (!precise) | 295 | if (!precise) |
| 296 | goto new_event; | 296 | goto new_event; |
| 297 | 297 | ||
| 298 | perf_event_attr__set_max_precise_ip(&attr); | ||
| 299 | /* | 298 | /* |
| 300 | * Now let the usual logic to set up the perf_event_attr defaults | 299 | * Now let the usual logic to set up the perf_event_attr defaults |
| 301 | * to kick in when we return and before perf_evsel__open() is called. | 300 | * to kick in when we return and before perf_evsel__open() is called. |
| @@ -305,6 +304,8 @@ new_event: | |||
| 305 | if (evsel == NULL) | 304 | if (evsel == NULL) |
| 306 | goto out; | 305 | goto out; |
| 307 | 306 | ||
| 307 | evsel->precise_max = true; | ||
| 308 | |||
| 308 | /* use asprintf() because free(evsel) assumes name is allocated */ | 309 | /* use asprintf() because free(evsel) assumes name is allocated */ |
| 309 | if (asprintf(&evsel->name, "cycles%s%s%.*s", | 310 | if (asprintf(&evsel->name, "cycles%s%s%.*s", |
| 310 | (attr.precise_ip || attr.exclude_kernel) ? ":" : "", | 311 | (attr.precise_ip || attr.exclude_kernel) ? ":" : "", |
| @@ -1083,7 +1084,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, | |||
| 1083 | } | 1084 | } |
| 1084 | 1085 | ||
| 1085 | if (evsel->precise_max) | 1086 | if (evsel->precise_max) |
| 1086 | perf_event_attr__set_max_precise_ip(attr); | 1087 | attr->precise_ip = 3; |
| 1087 | 1088 | ||
| 1088 | if (opts->all_user) { | 1089 | if (opts->all_user) { |
| 1089 | attr->exclude_kernel = 1; | 1090 | attr->exclude_kernel = 1; |
| @@ -1749,6 +1750,59 @@ static bool ignore_missing_thread(struct perf_evsel *evsel, | |||
| 1749 | return true; | 1750 | return true; |
| 1750 | } | 1751 | } |
| 1751 | 1752 | ||
| 1753 | static void display_attr(struct perf_event_attr *attr) | ||
| 1754 | { | ||
| 1755 | if (verbose >= 2) { | ||
| 1756 | fprintf(stderr, "%.60s\n", graph_dotted_line); | ||
| 1757 | fprintf(stderr, "perf_event_attr:\n"); | ||
| 1758 | perf_event_attr__fprintf(stderr, attr, __open_attr__fprintf, NULL); | ||
| 1759 | fprintf(stderr, "%.60s\n", graph_dotted_line); | ||
| 1760 | } | ||
| 1761 | } | ||
| 1762 | |||
| 1763 | static int perf_event_open(struct perf_evsel *evsel, | ||
| 1764 | pid_t pid, int cpu, int group_fd, | ||
| 1765 | unsigned long flags) | ||
| 1766 | { | ||
| 1767 | int precise_ip = evsel->attr.precise_ip; | ||
| 1768 | int fd; | ||
| 1769 | |||
| 1770 | while (1) { | ||
| 1771 | pr_debug2("sys_perf_event_open: pid %d cpu %d group_fd %d flags %#lx", | ||
| 1772 | pid, cpu, group_fd, flags); | ||
| 1773 | |||
| 1774 | fd = sys_perf_event_open(&evsel->attr, pid, cpu, group_fd, flags); | ||
| 1775 | if (fd >= 0) | ||
| 1776 | break; | ||
| 1777 | |||
| 1778 | /* | ||
| 1779 | * Do quick precise_ip fallback if: | ||
| 1780 | * - there is precise_ip set in perf_event_attr | ||
| 1781 | * - maximum precise is requested | ||
| 1782 | * - sys_perf_event_open failed with ENOTSUP error, | ||
| 1783 | * which is associated with wrong precise_ip | ||
| 1784 | */ | ||
| 1785 | if (!precise_ip || !evsel->precise_max || (errno != ENOTSUP)) | ||
| 1786 | break; | ||
| 1787 | |||
| 1788 | /* | ||
| 1789 | * We tried all the precise_ip values, and it's | ||
| 1790 | * still failing, so leave it to standard fallback. | ||
| 1791 | */ | ||
| 1792 | if (!evsel->attr.precise_ip) { | ||
| 1793 | evsel->attr.precise_ip = precise_ip; | ||
| 1794 | break; | ||
| 1795 | } | ||
| 1796 | |||
| 1797 | pr_debug2("\nsys_perf_event_open failed, error %d\n", -ENOTSUP); | ||
| 1798 | evsel->attr.precise_ip--; | ||
| 1799 | pr_debug2("decreasing precise_ip by one (%d)\n", evsel->attr.precise_ip); | ||
| 1800 | display_attr(&evsel->attr); | ||
| 1801 | } | ||
| 1802 | |||
| 1803 | return fd; | ||
| 1804 | } | ||
| 1805 | |||
| 1752 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 1806 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
| 1753 | struct thread_map *threads) | 1807 | struct thread_map *threads) |
| 1754 | { | 1808 | { |
| @@ -1824,12 +1878,7 @@ retry_sample_id: | |||
| 1824 | if (perf_missing_features.sample_id_all) | 1878 | if (perf_missing_features.sample_id_all) |
| 1825 | evsel->attr.sample_id_all = 0; | 1879 | evsel->attr.sample_id_all = 0; |
| 1826 | 1880 | ||
| 1827 | if (verbose >= 2) { | 1881 | display_attr(&evsel->attr); |
| 1828 | fprintf(stderr, "%.60s\n", graph_dotted_line); | ||
| 1829 | fprintf(stderr, "perf_event_attr:\n"); | ||
| 1830 | perf_event_attr__fprintf(stderr, &evsel->attr, __open_attr__fprintf, NULL); | ||
| 1831 | fprintf(stderr, "%.60s\n", graph_dotted_line); | ||
| 1832 | } | ||
| 1833 | 1882 | ||
| 1834 | for (cpu = 0; cpu < cpus->nr; cpu++) { | 1883 | for (cpu = 0; cpu < cpus->nr; cpu++) { |
| 1835 | 1884 | ||
| @@ -1841,13 +1890,10 @@ retry_sample_id: | |||
| 1841 | 1890 | ||
| 1842 | group_fd = get_group_fd(evsel, cpu, thread); | 1891 | group_fd = get_group_fd(evsel, cpu, thread); |
| 1843 | retry_open: | 1892 | retry_open: |
| 1844 | pr_debug2("sys_perf_event_open: pid %d cpu %d group_fd %d flags %#lx", | ||
| 1845 | pid, cpus->map[cpu], group_fd, flags); | ||
| 1846 | |||
| 1847 | test_attr__ready(); | 1893 | test_attr__ready(); |
| 1848 | 1894 | ||
| 1849 | fd = sys_perf_event_open(&evsel->attr, pid, cpus->map[cpu], | 1895 | fd = perf_event_open(evsel, pid, cpus->map[cpu], |
| 1850 | group_fd, flags); | 1896 | group_fd, flags); |
| 1851 | 1897 | ||
| 1852 | FD(evsel, cpu, thread) = fd; | 1898 | FD(evsel, cpu, thread) = fd; |
| 1853 | 1899 | ||
