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

Configure Feed

Select the types of activity you want to include in your feed.

perf pmus: Sort/merge/aggregate PMUs like mrvl_ddr_pmu

The mrvl_ddr_pmu is uncore and has a hexadecimal address suffix while
the previous PMU sorting/merging code assumes uncore PMU names start
with uncore_ and have a decimal suffix. Because of the previous
assumption it isn't possible to wildcard the mrvl_ddr_pmu.

Modify pmu_name_len_no_suffix but also remove the suffix number out
argument, this is because we don't know if a suffix number of say 100
is in hexadecimal or decimal. As the only use of the suffix number is
in comparisons, it is safe there to compare the values as hexadecimal.
Modify perf_pmu__match_ignoring_suffix so that hexadecimal suffixes
are ignored.

Only allow hexadecimal suffixes to be greater than length 2 (ie 3 or
more) so that S390's cpum_cf PMU doesn't lose its suffix.

Change the return type of pmu_name_len_no_suffix to size_t to
workaround GCC incorrectly determining the result could be negative.

Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: James Clark <james.clark@arm.com>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Will Deacon <will@kernel.org>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Cc: Bharat Bhushan <bbhushan2@marvell.com>
Cc: Bhaskara Budiredla <bbudiredla@marvell.com>
Cc: Tuan Phan <tuanphan@os.amperecomputing.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/r/20240515060114.3268149-2-irogers@google.com

authored by

Ian Rogers and committed by
Namhyung Kim
3241d46f 1613e604

+65 -42
+20 -13
tools/perf/util/pmu.c
··· 856 856 */ 857 857 static bool perf_pmu__match_ignoring_suffix(const char *pmu_name, const char *tok) 858 858 { 859 - const char *p; 859 + const char *p, *suffix; 860 + bool has_hex = false; 860 861 861 862 if (strncmp(pmu_name, tok, strlen(tok))) 862 863 return false; 863 864 864 - p = pmu_name + strlen(tok); 865 + suffix = p = pmu_name + strlen(tok); 865 866 if (*p == 0) 866 867 return true; 867 868 868 - if (*p == '_') 869 + if (*p == '_') { 869 870 ++p; 871 + ++suffix; 872 + } 870 873 871 874 /* Ensure we end in a number */ 872 875 while (1) { 873 - if (!isdigit(*p)) 876 + if (!isxdigit(*p)) 874 877 return false; 878 + if (!has_hex) 879 + has_hex = !isdigit(*p); 875 880 if (*(++p) == 0) 876 881 break; 877 882 } 883 + 884 + if (has_hex) 885 + return (p - suffix) > 2; 878 886 879 887 return true; 880 888 } ··· 1796 1788 const struct perf_pmu_alias *alias, bool skip_duplicate_pmus) 1797 1789 { 1798 1790 struct parse_events_term *term; 1799 - int pmu_name_len = skip_duplicate_pmus 1800 - ? pmu_name_len_no_suffix(pmu->name, /*num=*/NULL) 1801 - : (int)strlen(pmu->name); 1802 - int used = snprintf(buf, len, "%.*s/%s", pmu_name_len, pmu->name, alias->name); 1791 + size_t pmu_name_len = skip_duplicate_pmus 1792 + ? pmu_name_len_no_suffix(pmu->name) 1793 + : strlen(pmu->name); 1794 + int used = snprintf(buf, len, "%.*s/%s", (int)pmu_name_len, pmu->name, alias->name); 1803 1795 1804 1796 list_for_each_entry(term, &alias->terms.terms, list) { 1805 1797 if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) ··· 1836 1828 pmu_aliases_parse(pmu); 1837 1829 pmu_add_cpu_aliases(pmu); 1838 1830 list_for_each_entry(event, &pmu->aliases, list) { 1839 - size_t buf_used; 1840 - int pmu_name_len; 1831 + size_t buf_used, pmu_name_len; 1841 1832 1842 1833 info.pmu_name = event->pmu_name ?: pmu->name; 1843 1834 pmu_name_len = skip_duplicate_pmus 1844 - ? pmu_name_len_no_suffix(info.pmu_name, /*num=*/NULL) 1845 - : (int)strlen(info.pmu_name); 1835 + ? pmu_name_len_no_suffix(info.pmu_name) 1836 + : strlen(info.pmu_name); 1846 1837 info.alias = NULL; 1847 1838 if (event->desc) { 1848 1839 info.name = event->name; ··· 1866 1859 info.encoding_desc = buf + buf_used; 1867 1860 parse_events_terms__to_strbuf(&event->terms, &sb); 1868 1861 buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used, 1869 - "%.*s/%s/", pmu_name_len, info.pmu_name, sb.buf) + 1; 1862 + "%.*s/%s/", (int)pmu_name_len, info.pmu_name, sb.buf) + 1; 1870 1863 info.topic = event->topic; 1871 1864 info.str = sb.buf; 1872 1865 info.deprecated = event->deprecated;
+39 -28
tools/perf/util/pmus.c
··· 40 40 41 41 static void pmu_read_sysfs(bool core_only); 42 42 43 - int pmu_name_len_no_suffix(const char *str, unsigned long *num) 43 + size_t pmu_name_len_no_suffix(const char *str) 44 44 { 45 45 int orig_len, len; 46 + bool has_hex_digits = false; 46 47 47 48 orig_len = len = strlen(str); 48 49 49 - /* Non-uncore PMUs have their full length, for example, i915. */ 50 - if (!strstarts(str, "uncore_")) 51 - return len; 52 - 53 - /* 54 - * Count trailing digits and '_', if '_{num}' suffix isn't present use 55 - * the full length. 56 - */ 57 - while (len > 0 && isdigit(str[len - 1])) 50 + /* Count trailing digits. */ 51 + while (len > 0 && isxdigit(str[len - 1])) { 52 + if (!isdigit(str[len - 1])) 53 + has_hex_digits = true; 58 54 len--; 55 + } 59 56 60 57 if (len > 0 && len != orig_len && str[len - 1] == '_') { 61 - if (num) 62 - *num = strtoul(&str[len], NULL, 10); 63 - return len - 1; 58 + /* 59 + * There is a '_{num}' suffix. For decimal suffixes any length 60 + * will do, for hexadecimal ensure more than 2 hex digits so 61 + * that S390's cpum_cf PMU doesn't match. 62 + */ 63 + if (!has_hex_digits || (orig_len - len) > 2) 64 + return len - 1; 64 65 } 66 + /* Use the full length. */ 65 67 return orig_len; 68 + } 69 + 70 + int pmu_name_cmp(const char *lhs_pmu_name, const char *rhs_pmu_name) 71 + { 72 + unsigned long lhs_num = 0, rhs_num = 0; 73 + size_t lhs_pmu_name_len = pmu_name_len_no_suffix(lhs_pmu_name); 74 + size_t rhs_pmu_name_len = pmu_name_len_no_suffix(rhs_pmu_name); 75 + int ret = strncmp(lhs_pmu_name, rhs_pmu_name, 76 + lhs_pmu_name_len < rhs_pmu_name_len ? lhs_pmu_name_len : rhs_pmu_name_len); 77 + 78 + if (lhs_pmu_name_len != rhs_pmu_name_len || ret != 0 || lhs_pmu_name_len == 0) 79 + return ret; 80 + 81 + if (lhs_pmu_name_len + 1 < strlen(lhs_pmu_name)) 82 + lhs_num = strtoul(&lhs_pmu_name[lhs_pmu_name_len + 1], NULL, 16); 83 + if (rhs_pmu_name_len + 1 < strlen(rhs_pmu_name)) 84 + rhs_num = strtoul(&rhs_pmu_name[rhs_pmu_name_len + 1], NULL, 16); 85 + 86 + return lhs_num < rhs_num ? -1 : (lhs_num > rhs_num ? 1 : 0); 66 87 } 67 88 68 89 void perf_pmus__destroy(void) ··· 188 167 static int pmus_cmp(void *priv __maybe_unused, 189 168 const struct list_head *lhs, const struct list_head *rhs) 190 169 { 191 - unsigned long lhs_num = 0, rhs_num = 0; 192 170 struct perf_pmu *lhs_pmu = container_of(lhs, struct perf_pmu, list); 193 171 struct perf_pmu *rhs_pmu = container_of(rhs, struct perf_pmu, list); 194 - const char *lhs_pmu_name = lhs_pmu->name ?: ""; 195 - const char *rhs_pmu_name = rhs_pmu->name ?: ""; 196 - int lhs_pmu_name_len = pmu_name_len_no_suffix(lhs_pmu_name, &lhs_num); 197 - int rhs_pmu_name_len = pmu_name_len_no_suffix(rhs_pmu_name, &rhs_num); 198 - int ret = strncmp(lhs_pmu_name, rhs_pmu_name, 199 - lhs_pmu_name_len < rhs_pmu_name_len ? lhs_pmu_name_len : rhs_pmu_name_len); 200 172 201 - if (lhs_pmu_name_len != rhs_pmu_name_len || ret != 0 || lhs_pmu_name_len == 0) 202 - return ret; 203 - 204 - return lhs_num < rhs_num ? -1 : (lhs_num > rhs_num ? 1 : 0); 173 + return pmu_name_cmp(lhs_pmu->name ?: "", rhs_pmu->name ?: ""); 205 174 } 206 175 207 176 /* Add all pmus in sysfs to pmu list: */ ··· 311 300 pmu_read_sysfs(/*core_only=*/false); 312 301 pmu = list_prepare_entry(pmu, &core_pmus, list); 313 302 } else 314 - last_pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: "", NULL); 303 + last_pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: ""); 315 304 316 305 if (use_core_pmus) { 317 306 list_for_each_entry_continue(pmu, &core_pmus, list) { 318 - int pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: "", /*num=*/NULL); 307 + int pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: ""); 319 308 320 309 if (last_pmu_name_len == pmu_name_len && 321 310 !strncmp(last_pmu_name, pmu->name ?: "", pmu_name_len)) ··· 327 316 pmu = list_prepare_entry(pmu, &other_pmus, list); 328 317 } 329 318 list_for_each_entry_continue(pmu, &other_pmus, list) { 330 - int pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: "", /*num=*/NULL); 319 + int pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: ""); 331 320 332 321 if (last_pmu_name_len == pmu_name_len && 333 322 !strncmp(last_pmu_name, pmu->name ?: "", pmu_name_len)) ··· 577 566 .long_string = STRBUF_INIT, 578 567 .num_formats = 0, 579 568 }; 580 - int len = pmu_name_len_no_suffix(pmu->name, /*num=*/NULL); 569 + int len = pmu_name_len_no_suffix(pmu->name); 581 570 const char *desc = "(see 'man perf-list' or 'man perf-record' on how to encode it)"; 582 571 583 572 if (!pmu->is_core)
+6 -1
tools/perf/util/pmus.h
··· 2 2 #ifndef __PMUS_H 3 3 #define __PMUS_H 4 4 5 + #include <stdbool.h> 6 + #include <stddef.h> 7 + 5 8 struct perf_pmu; 6 9 struct print_callbacks; 7 10 8 - int pmu_name_len_no_suffix(const char *str, unsigned long *num); 11 + size_t pmu_name_len_no_suffix(const char *str); 12 + /* Exposed for testing only. */ 13 + int pmu_name_cmp(const char *lhs_pmu_name, const char *rhs_pmu_name); 9 14 10 15 void perf_pmus__destroy(void); 11 16