aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/sort.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/sort.c')
-rw-r--r--tools/perf/util/sort.c601
1 files changed, 590 insertions, 11 deletions
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 2d8ccd4d9e1b..ec722346e6ff 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -4,6 +4,8 @@
4#include "comm.h" 4#include "comm.h"
5#include "symbol.h" 5#include "symbol.h"
6#include "evsel.h" 6#include "evsel.h"
7#include "evlist.h"
8#include <traceevent/event-parse.h>
7 9
8regex_t parent_regex; 10regex_t parent_regex;
9const char default_parent_pattern[] = "^sys_|^do_page_fault"; 11const char default_parent_pattern[] = "^sys_|^do_page_fault";
@@ -13,6 +15,7 @@ const char default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cy
13const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked"; 15const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
14const char default_top_sort_order[] = "dso,symbol"; 16const char default_top_sort_order[] = "dso,symbol";
15const char default_diff_sort_order[] = "dso,symbol"; 17const char default_diff_sort_order[] = "dso,symbol";
18const char default_tracepoint_sort_order[] = "trace";
16const char *sort_order; 19const char *sort_order;
17const char *field_order; 20const char *field_order;
18regex_t ignore_callees_regex; 21regex_t ignore_callees_regex;
@@ -443,6 +446,70 @@ struct sort_entry sort_socket = {
443 .se_width_idx = HISTC_SOCKET, 446 .se_width_idx = HISTC_SOCKET,
444}; 447};
445 448
449/* --sort trace */
450
451static char *get_trace_output(struct hist_entry *he)
452{
453 struct trace_seq seq;
454 struct perf_evsel *evsel;
455 struct pevent_record rec = {
456 .data = he->raw_data,
457 .size = he->raw_size,
458 };
459
460 evsel = hists_to_evsel(he->hists);
461
462 trace_seq_init(&seq);
463 if (symbol_conf.raw_trace) {
464 pevent_print_fields(&seq, he->raw_data, he->raw_size,
465 evsel->tp_format);
466 } else {
467 pevent_event_info(&seq, evsel->tp_format, &rec);
468 }
469 return seq.buffer;
470}
471
472static int64_t
473sort__trace_cmp(struct hist_entry *left, struct hist_entry *right)
474{
475 struct perf_evsel *evsel;
476
477 evsel = hists_to_evsel(left->hists);
478 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
479 return 0;
480
481 if (left->trace_output == NULL)
482 left->trace_output = get_trace_output(left);
483 if (right->trace_output == NULL)
484 right->trace_output = get_trace_output(right);
485
486 hists__new_col_len(left->hists, HISTC_TRACE, strlen(left->trace_output));
487 hists__new_col_len(right->hists, HISTC_TRACE, strlen(right->trace_output));
488
489 return strcmp(right->trace_output, left->trace_output);
490}
491
492static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf,
493 size_t size, unsigned int width)
494{
495 struct perf_evsel *evsel;
496
497 evsel = hists_to_evsel(he->hists);
498 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
499 return scnprintf(bf, size, "%-*.*s", width, width, "N/A");
500
501 if (he->trace_output == NULL)
502 he->trace_output = get_trace_output(he);
503 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->trace_output);
504}
505
506struct sort_entry sort_trace = {
507 .se_header = "Trace output",
508 .se_cmp = sort__trace_cmp,
509 .se_snprintf = hist_entry__trace_snprintf,
510 .se_width_idx = HISTC_TRACE,
511};
512
446/* sort keys for branch stacks */ 513/* sort keys for branch stacks */
447 514
448static int64_t 515static int64_t
@@ -1312,6 +1379,7 @@ static struct sort_dimension common_sort_dimensions[] = {
1312 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), 1379 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1313 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), 1380 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
1314 DIM(SORT_TRANSACTION, "transaction", sort_transaction), 1381 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
1382 DIM(SORT_TRACE, "trace", sort_trace),
1315}; 1383};
1316 1384
1317#undef DIM 1385#undef DIM
@@ -1529,6 +1597,455 @@ static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1529 return 0; 1597 return 0;
1530} 1598}
1531 1599
1600struct hpp_dynamic_entry {
1601 struct perf_hpp_fmt hpp;
1602 struct perf_evsel *evsel;
1603 struct format_field *field;
1604 unsigned dynamic_len;
1605 bool raw_trace;
1606};
1607
1608static int hde_width(struct hpp_dynamic_entry *hde)
1609{
1610 if (!hde->hpp.len) {
1611 int len = hde->dynamic_len;
1612 int namelen = strlen(hde->field->name);
1613 int fieldlen = hde->field->size;
1614
1615 if (namelen > len)
1616 len = namelen;
1617
1618 if (!(hde->field->flags & FIELD_IS_STRING)) {
1619 /* length for print hex numbers */
1620 fieldlen = hde->field->size * 2 + 2;
1621 }
1622 if (fieldlen > len)
1623 len = fieldlen;
1624
1625 hde->hpp.len = len;
1626 }
1627 return hde->hpp.len;
1628}
1629
1630static void update_dynamic_len(struct hpp_dynamic_entry *hde,
1631 struct hist_entry *he)
1632{
1633 char *str, *pos;
1634 struct format_field *field = hde->field;
1635 size_t namelen;
1636 bool last = false;
1637
1638 if (hde->raw_trace)
1639 return;
1640
1641 /* parse pretty print result and update max length */
1642 if (!he->trace_output)
1643 he->trace_output = get_trace_output(he);
1644
1645 namelen = strlen(field->name);
1646 str = he->trace_output;
1647
1648 while (str) {
1649 pos = strchr(str, ' ');
1650 if (pos == NULL) {
1651 last = true;
1652 pos = str + strlen(str);
1653 }
1654
1655 if (!strncmp(str, field->name, namelen)) {
1656 size_t len;
1657
1658 str += namelen + 1;
1659 len = pos - str;
1660
1661 if (len > hde->dynamic_len)
1662 hde->dynamic_len = len;
1663 break;
1664 }
1665
1666 if (last)
1667 str = NULL;
1668 else
1669 str = pos + 1;
1670 }
1671}
1672
1673static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1674 struct perf_evsel *evsel __maybe_unused)
1675{
1676 struct hpp_dynamic_entry *hde;
1677 size_t len = fmt->user_len;
1678
1679 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1680
1681 if (!len)
1682 len = hde_width(hde);
1683
1684 return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, hde->field->name);
1685}
1686
1687static int __sort__hde_width(struct perf_hpp_fmt *fmt,
1688 struct perf_hpp *hpp __maybe_unused,
1689 struct perf_evsel *evsel __maybe_unused)
1690{
1691 struct hpp_dynamic_entry *hde;
1692 size_t len = fmt->user_len;
1693
1694 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1695
1696 if (!len)
1697 len = hde_width(hde);
1698
1699 return len;
1700}
1701
1702bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists)
1703{
1704 struct hpp_dynamic_entry *hde;
1705
1706 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1707
1708 return hists_to_evsel(hists) == hde->evsel;
1709}
1710
1711static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1712 struct hist_entry *he)
1713{
1714 struct hpp_dynamic_entry *hde;
1715 size_t len = fmt->user_len;
1716 char *str, *pos;
1717 struct format_field *field;
1718 size_t namelen;
1719 bool last = false;
1720 int ret;
1721
1722 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1723
1724 if (!len)
1725 len = hde_width(hde);
1726
1727 if (hde->raw_trace)
1728 goto raw_field;
1729
1730 field = hde->field;
1731 namelen = strlen(field->name);
1732 str = he->trace_output;
1733
1734 while (str) {
1735 pos = strchr(str, ' ');
1736 if (pos == NULL) {
1737 last = true;
1738 pos = str + strlen(str);
1739 }
1740
1741 if (!strncmp(str, field->name, namelen)) {
1742 str += namelen + 1;
1743 str = strndup(str, pos - str);
1744
1745 if (str == NULL)
1746 return scnprintf(hpp->buf, hpp->size,
1747 "%*.*s", len, len, "ERROR");
1748 break;
1749 }
1750
1751 if (last)
1752 str = NULL;
1753 else
1754 str = pos + 1;
1755 }
1756
1757 if (str == NULL) {
1758 struct trace_seq seq;
1759raw_field:
1760 trace_seq_init(&seq);
1761 pevent_print_field(&seq, he->raw_data, hde->field);
1762 str = seq.buffer;
1763 }
1764
1765 ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, str);
1766 free(str);
1767 return ret;
1768}
1769
1770static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
1771 struct hist_entry *a, struct hist_entry *b)
1772{
1773 struct hpp_dynamic_entry *hde;
1774 struct format_field *field;
1775 unsigned offset, size;
1776
1777 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1778
1779 field = hde->field;
1780 if (field->flags & FIELD_IS_DYNAMIC) {
1781 unsigned long long dyn;
1782
1783 pevent_read_number_field(field, a->raw_data, &dyn);
1784 offset = dyn & 0xffff;
1785 size = (dyn >> 16) & 0xffff;
1786
1787 /* record max width for output */
1788 if (size > hde->dynamic_len)
1789 hde->dynamic_len = size;
1790 } else {
1791 offset = field->offset;
1792 size = field->size;
1793
1794 update_dynamic_len(hde, a);
1795 update_dynamic_len(hde, b);
1796 }
1797
1798 return memcmp(a->raw_data + offset, b->raw_data + offset, size);
1799}
1800
1801bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt)
1802{
1803 return fmt->cmp == __sort__hde_cmp;
1804}
1805
1806static struct hpp_dynamic_entry *
1807__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field)
1808{
1809 struct hpp_dynamic_entry *hde;
1810
1811 hde = malloc(sizeof(*hde));
1812 if (hde == NULL) {
1813 pr_debug("Memory allocation failed\n");
1814 return NULL;
1815 }
1816
1817 hde->evsel = evsel;
1818 hde->field = field;
1819 hde->dynamic_len = 0;
1820
1821 hde->hpp.name = field->name;
1822 hde->hpp.header = __sort__hde_header;
1823 hde->hpp.width = __sort__hde_width;
1824 hde->hpp.entry = __sort__hde_entry;
1825 hde->hpp.color = NULL;
1826
1827 hde->hpp.cmp = __sort__hde_cmp;
1828 hde->hpp.collapse = __sort__hde_cmp;
1829 hde->hpp.sort = __sort__hde_cmp;
1830
1831 INIT_LIST_HEAD(&hde->hpp.list);
1832 INIT_LIST_HEAD(&hde->hpp.sort_list);
1833 hde->hpp.elide = false;
1834 hde->hpp.len = 0;
1835 hde->hpp.user_len = 0;
1836
1837 return hde;
1838}
1839
1840static int parse_field_name(char *str, char **event, char **field, char **opt)
1841{
1842 char *event_name, *field_name, *opt_name;
1843
1844 event_name = str;
1845 field_name = strchr(str, '.');
1846
1847 if (field_name) {
1848 *field_name++ = '\0';
1849 } else {
1850 event_name = NULL;
1851 field_name = str;
1852 }
1853
1854 opt_name = strchr(field_name, '/');
1855 if (opt_name)
1856 *opt_name++ = '\0';
1857
1858 *event = event_name;
1859 *field = field_name;
1860 *opt = opt_name;
1861
1862 return 0;
1863}
1864
1865/* find match evsel using a given event name. The event name can be:
1866 * 1. '%' + event index (e.g. '%1' for first event)
1867 * 2. full event name (e.g. sched:sched_switch)
1868 * 3. partial event name (should not contain ':')
1869 */
1870static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_name)
1871{
1872 struct perf_evsel *evsel = NULL;
1873 struct perf_evsel *pos;
1874 bool full_name;
1875
1876 /* case 1 */
1877 if (event_name[0] == '%') {
1878 int nr = strtol(event_name+1, NULL, 0);
1879
1880 if (nr > evlist->nr_entries)
1881 return NULL;
1882
1883 evsel = perf_evlist__first(evlist);
1884 while (--nr > 0)
1885 evsel = perf_evsel__next(evsel);
1886
1887 return evsel;
1888 }
1889
1890 full_name = !!strchr(event_name, ':');
1891 evlist__for_each(evlist, pos) {
1892 /* case 2 */
1893 if (full_name && !strcmp(pos->name, event_name))
1894 return pos;
1895 /* case 3 */
1896 if (!full_name && strstr(pos->name, event_name)) {
1897 if (evsel) {
1898 pr_debug("'%s' event is ambiguous: it can be %s or %s\n",
1899 event_name, evsel->name, pos->name);
1900 return NULL;
1901 }
1902 evsel = pos;
1903 }
1904 }
1905
1906 return evsel;
1907}
1908
1909static int __dynamic_dimension__add(struct perf_evsel *evsel,
1910 struct format_field *field,
1911 bool raw_trace)
1912{
1913 struct hpp_dynamic_entry *hde;
1914
1915 hde = __alloc_dynamic_entry(evsel, field);
1916 if (hde == NULL)
1917 return -ENOMEM;
1918
1919 hde->raw_trace = raw_trace;
1920
1921 perf_hpp__register_sort_field(&hde->hpp);
1922 return 0;
1923}
1924
1925static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace)
1926{
1927 int ret;
1928 struct format_field *field;
1929
1930 field = evsel->tp_format->format.fields;
1931 while (field) {
1932 ret = __dynamic_dimension__add(evsel, field, raw_trace);
1933 if (ret < 0)
1934 return ret;
1935
1936 field = field->next;
1937 }
1938 return 0;
1939}
1940
1941static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace)
1942{
1943 int ret;
1944 struct perf_evsel *evsel;
1945
1946 evlist__for_each(evlist, evsel) {
1947 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
1948 continue;
1949
1950 ret = add_evsel_fields(evsel, raw_trace);
1951 if (ret < 0)
1952 return ret;
1953 }
1954 return 0;
1955}
1956
1957static int add_all_matching_fields(struct perf_evlist *evlist,
1958 char *field_name, bool raw_trace)
1959{
1960 int ret = -ESRCH;
1961 struct perf_evsel *evsel;
1962 struct format_field *field;
1963
1964 evlist__for_each(evlist, evsel) {
1965 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
1966 continue;
1967
1968 field = pevent_find_any_field(evsel->tp_format, field_name);
1969 if (field == NULL)
1970 continue;
1971
1972 ret = __dynamic_dimension__add(evsel, field, raw_trace);
1973 if (ret < 0)
1974 break;
1975 }
1976 return ret;
1977}
1978
1979static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
1980{
1981 char *str, *event_name, *field_name, *opt_name;
1982 struct perf_evsel *evsel;
1983 struct format_field *field;
1984 bool raw_trace = symbol_conf.raw_trace;
1985 int ret = 0;
1986
1987 if (evlist == NULL)
1988 return -ENOENT;
1989
1990 str = strdup(tok);
1991 if (str == NULL)
1992 return -ENOMEM;
1993
1994 if (parse_field_name(str, &event_name, &field_name, &opt_name) < 0) {
1995 ret = -EINVAL;
1996 goto out;
1997 }
1998
1999 if (opt_name) {
2000 if (strcmp(opt_name, "raw")) {
2001 pr_debug("unsupported field option %s\n", opt_name);
2002 ret = -EINVAL;
2003 goto out;
2004 }
2005 raw_trace = true;
2006 }
2007
2008 if (!strcmp(field_name, "trace_fields")) {
2009 ret = add_all_dynamic_fields(evlist, raw_trace);
2010 goto out;
2011 }
2012
2013 if (event_name == NULL) {
2014 ret = add_all_matching_fields(evlist, field_name, raw_trace);
2015 goto out;
2016 }
2017
2018 evsel = find_evsel(evlist, event_name);
2019 if (evsel == NULL) {
2020 pr_debug("Cannot find event: %s\n", event_name);
2021 ret = -ENOENT;
2022 goto out;
2023 }
2024
2025 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2026 pr_debug("%s is not a tracepoint event\n", event_name);
2027 ret = -EINVAL;
2028 goto out;
2029 }
2030
2031 if (!strcmp(field_name, "*")) {
2032 ret = add_evsel_fields(evsel, raw_trace);
2033 } else {
2034 field = pevent_find_any_field(evsel->tp_format, field_name);
2035 if (field == NULL) {
2036 pr_debug("Cannot find event field for %s.%s\n",
2037 event_name, field_name);
2038 return -ENOENT;
2039 }
2040
2041 ret = __dynamic_dimension__add(evsel, field, raw_trace);
2042 }
2043
2044out:
2045 free(str);
2046 return ret;
2047}
2048
1532static int __sort_dimension__add(struct sort_dimension *sd) 2049static int __sort_dimension__add(struct sort_dimension *sd)
1533{ 2050{
1534 if (sd->taken) 2051 if (sd->taken)
@@ -1583,7 +2100,8 @@ int hpp_dimension__add_output(unsigned col)
1583 return __hpp_dimension__add_output(&hpp_sort_dimensions[col]); 2100 return __hpp_dimension__add_output(&hpp_sort_dimensions[col]);
1584} 2101}
1585 2102
1586int sort_dimension__add(const char *tok) 2103static int sort_dimension__add(const char *tok,
2104 struct perf_evlist *evlist __maybe_unused)
1587{ 2105{
1588 unsigned int i; 2106 unsigned int i;
1589 2107
@@ -1664,10 +2182,13 @@ int sort_dimension__add(const char *tok)
1664 return 0; 2182 return 0;
1665 } 2183 }
1666 2184
2185 if (!add_dynamic_entry(evlist, tok))
2186 return 0;
2187
1667 return -ESRCH; 2188 return -ESRCH;
1668} 2189}
1669 2190
1670static const char *get_default_sort_order(void) 2191static const char *get_default_sort_order(struct perf_evlist *evlist)
1671{ 2192{
1672 const char *default_sort_orders[] = { 2193 const char *default_sort_orders[] = {
1673 default_sort_order, 2194 default_sort_order,
@@ -1675,14 +2196,33 @@ static const char *get_default_sort_order(void)
1675 default_mem_sort_order, 2196 default_mem_sort_order,
1676 default_top_sort_order, 2197 default_top_sort_order,
1677 default_diff_sort_order, 2198 default_diff_sort_order,
2199 default_tracepoint_sort_order,
1678 }; 2200 };
2201 bool use_trace = true;
2202 struct perf_evsel *evsel;
1679 2203
1680 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders)); 2204 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1681 2205
2206 if (evlist == NULL)
2207 goto out_no_evlist;
2208
2209 evlist__for_each(evlist, evsel) {
2210 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2211 use_trace = false;
2212 break;
2213 }
2214 }
2215
2216 if (use_trace) {
2217 sort__mode = SORT_MODE__TRACEPOINT;
2218 if (symbol_conf.raw_trace)
2219 return "trace_fields";
2220 }
2221out_no_evlist:
1682 return default_sort_orders[sort__mode]; 2222 return default_sort_orders[sort__mode];
1683} 2223}
1684 2224
1685static int setup_sort_order(void) 2225static int setup_sort_order(struct perf_evlist *evlist)
1686{ 2226{
1687 char *new_sort_order; 2227 char *new_sort_order;
1688 2228
@@ -1703,7 +2243,7 @@ static int setup_sort_order(void)
1703 * because it's checked over the rest of the code. 2243 * because it's checked over the rest of the code.
1704 */ 2244 */
1705 if (asprintf(&new_sort_order, "%s,%s", 2245 if (asprintf(&new_sort_order, "%s,%s",
1706 get_default_sort_order(), sort_order + 1) < 0) { 2246 get_default_sort_order(evlist), sort_order + 1) < 0) {
1707 error("Not enough memory to set up --sort"); 2247 error("Not enough memory to set up --sort");
1708 return -ENOMEM; 2248 return -ENOMEM;
1709 } 2249 }
@@ -1712,13 +2252,41 @@ static int setup_sort_order(void)
1712 return 0; 2252 return 0;
1713} 2253}
1714 2254
1715static int __setup_sorting(void) 2255/*
2256 * Adds 'pre,' prefix into 'str' is 'pre' is
2257 * not already part of 'str'.
2258 */
2259static char *prefix_if_not_in(const char *pre, char *str)
2260{
2261 char *n;
2262
2263 if (!str || strstr(str, pre))
2264 return str;
2265
2266 if (asprintf(&n, "%s,%s", pre, str) < 0)
2267 return NULL;
2268
2269 free(str);
2270 return n;
2271}
2272
2273static char *setup_overhead(char *keys)
2274{
2275 keys = prefix_if_not_in("overhead", keys);
2276
2277 if (symbol_conf.cumulate_callchain)
2278 keys = prefix_if_not_in("overhead_children", keys);
2279
2280 return keys;
2281}
2282
2283static int __setup_sorting(struct perf_evlist *evlist)
1716{ 2284{
1717 char *tmp, *tok, *str; 2285 char *tmp, *tok, *str;
1718 const char *sort_keys; 2286 const char *sort_keys;
1719 int ret = 0; 2287 int ret = 0;
1720 2288
1721 ret = setup_sort_order(); 2289 ret = setup_sort_order(evlist);
1722 if (ret) 2290 if (ret)
1723 return ret; 2291 return ret;
1724 2292
@@ -1732,7 +2300,7 @@ static int __setup_sorting(void)
1732 return 0; 2300 return 0;
1733 } 2301 }
1734 2302
1735 sort_keys = get_default_sort_order(); 2303 sort_keys = get_default_sort_order(evlist);
1736 } 2304 }
1737 2305
1738 str = strdup(sort_keys); 2306 str = strdup(sort_keys);
@@ -1741,9 +2309,20 @@ static int __setup_sorting(void)
1741 return -ENOMEM; 2309 return -ENOMEM;
1742 } 2310 }
1743 2311
2312 /*
2313 * Prepend overhead fields for backward compatibility.
2314 */
2315 if (!is_strict_order(field_order)) {
2316 str = setup_overhead(str);
2317 if (str == NULL) {
2318 error("Not enough memory to setup overhead keys");
2319 return -ENOMEM;
2320 }
2321 }
2322
1744 for (tok = strtok_r(str, ", ", &tmp); 2323 for (tok = strtok_r(str, ", ", &tmp);
1745 tok; tok = strtok_r(NULL, ", ", &tmp)) { 2324 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1746 ret = sort_dimension__add(tok); 2325 ret = sort_dimension__add(tok, evlist);
1747 if (ret == -EINVAL) { 2326 if (ret == -EINVAL) {
1748 error("Invalid --sort key: `%s'", tok); 2327 error("Invalid --sort key: `%s'", tok);
1749 break; 2328 break;
@@ -1954,16 +2533,16 @@ out:
1954 return ret; 2533 return ret;
1955} 2534}
1956 2535
1957int setup_sorting(void) 2536int setup_sorting(struct perf_evlist *evlist)
1958{ 2537{
1959 int err; 2538 int err;
1960 2539
1961 err = __setup_sorting(); 2540 err = __setup_sorting(evlist);
1962 if (err < 0) 2541 if (err < 0)
1963 return err; 2542 return err;
1964 2543
1965 if (parent_pattern != default_parent_pattern) { 2544 if (parent_pattern != default_parent_pattern) {
1966 err = sort_dimension__add("parent"); 2545 err = sort_dimension__add("parent", evlist);
1967 if (err < 0) 2546 if (err < 0)
1968 return err; 2547 return err;
1969 } 2548 }