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

perf test: Use full metric resolution

The simple metric resolution doesn't handle recursion properly, switch
to use the full resolution as with the parse-metric tests which also
increases coverage. Don't set the values for the metric backward as
failures to generate a result are ignored.

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mike Leach <mike.leach@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Will Deacon <will@kernel.org>
Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com>
Cc: linux-arm-kernel@lists.infradead.org
Link: https://lore.kernel.org/r/20220812230949.683239-9-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
64234c14 29be2fe0

+77 -145
+77 -145
tools/perf/tests/pmu-events.c
··· 9 9 #include <linux/zalloc.h> 10 10 #include "debug.h" 11 11 #include "../pmu-events/pmu-events.h" 12 + #include <perf/evlist.h> 12 13 #include "util/evlist.h" 13 14 #include "util/expr.h" 14 15 #include "util/parse-events.h" 15 16 #include "metricgroup.h" 17 + #include "stat.h" 16 18 17 19 struct perf_pmu_test_event { 18 20 /* used for matching against events from generated pmu-events.c */ ··· 803 801 return ret; 804 802 } 805 803 806 - static int check_parse_cpu(const char *id, bool same_cpu, const struct pmu_event *pe) 807 - { 808 - struct parse_events_error error; 809 - int ret; 810 - 811 - parse_events_error__init(&error); 812 - ret = check_parse_id(id, &error, NULL); 813 - if (ret && same_cpu) { 814 - pr_warning("Parse event failed metric '%s' id '%s' expr '%s'\n", 815 - pe->metric_name, id, pe->metric_expr); 816 - pr_warning("Error string '%s' help '%s'\n", error.str, 817 - error.help); 818 - } else if (ret) { 819 - pr_debug3("Parse event failed, but for an event that may not be supported by this CPU.\nid '%s' metric '%s' expr '%s'\n", 820 - id, pe->metric_name, pe->metric_expr); 821 - ret = 0; 822 - } 823 - parse_events_error__exit(&error); 824 - return ret; 825 - } 826 - 827 804 static int check_parse_fake(const char *id) 828 805 { 829 806 struct parse_events_error error; ··· 819 838 struct metric_ref metric_ref; 820 839 }; 821 840 822 - static int resolve_metric_simple(struct expr_parse_ctx *pctx, 823 - struct list_head *compound_list, 824 - const struct pmu_event *map, 825 - const char *metric_name) 826 - { 827 - struct hashmap_entry *cur, *cur_tmp; 828 - struct metric *metric, *tmp; 829 - size_t bkt; 830 - bool all; 831 - int rc; 832 - 833 - do { 834 - all = true; 835 - hashmap__for_each_entry_safe(pctx->ids, cur, cur_tmp, bkt) { 836 - struct metric_ref *ref; 837 - const struct pmu_event *pe; 838 - 839 - pe = metricgroup__find_metric(cur->key, map); 840 - if (!pe) 841 - continue; 842 - 843 - if (!strcmp(metric_name, (char *)cur->key)) { 844 - pr_warning("Recursion detected for metric %s\n", metric_name); 845 - rc = -1; 846 - goto out_err; 847 - } 848 - 849 - all = false; 850 - 851 - /* The metric key itself needs to go out.. */ 852 - expr__del_id(pctx, cur->key); 853 - 854 - metric = malloc(sizeof(*metric)); 855 - if (!metric) { 856 - rc = -ENOMEM; 857 - goto out_err; 858 - } 859 - 860 - ref = &metric->metric_ref; 861 - ref->metric_name = pe->metric_name; 862 - ref->metric_expr = pe->metric_expr; 863 - list_add_tail(&metric->list, compound_list); 864 - 865 - rc = expr__find_ids(pe->metric_expr, NULL, pctx); 866 - if (rc) 867 - goto out_err; 868 - break; /* The hashmap has been modified, so restart */ 869 - } 870 - } while (!all); 871 - 872 - return 0; 873 - 874 - out_err: 875 - list_for_each_entry_safe(metric, tmp, compound_list, list) 876 - free(metric); 877 - 878 - return rc; 879 - 880 - } 881 - 882 - static void expr_failure(const char *msg, const struct pmu_event *pe) 883 - { 884 - pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr); 885 - } 886 - 887 - 888 - struct test__parsing_data { 889 - const struct pmu_event *cpus_table; 890 - struct expr_parse_ctx *ctx; 891 - int failures; 892 - }; 893 - 894 841 static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_event *table, 895 - void *vdata) 842 + void *data) 896 843 { 897 - struct test__parsing_data *data = vdata; 898 - struct metric *metric, *tmp; 899 - struct hashmap_entry *cur; 900 - LIST_HEAD(compound_list); 901 - size_t bkt; 844 + int *failures = data; 902 845 int k; 903 - double result; 846 + struct evlist *evlist; 847 + struct perf_cpu_map *cpus; 848 + struct runtime_stat st; 849 + struct evsel *evsel; 850 + struct rblist metric_events = { 851 + .nr_entries = 0, 852 + }; 853 + int err = 0; 904 854 905 855 if (!pe->metric_expr) 906 856 return 0; 907 857 908 858 pr_debug("Found metric '%s'\n", pe->metric_name); 859 + (*failures)++; 909 860 910 - expr__ctx_clear(data->ctx); 911 - if (expr__find_ids(pe->metric_expr, NULL, data->ctx) < 0) { 912 - expr_failure("Parse find ids failed", pe); 913 - data->failures++; 914 - return 0; 861 + /* 862 + * We need to prepare evlist for stat mode running on CPU 0 863 + * because that's where all the stats are going to be created. 864 + */ 865 + evlist = evlist__new(); 866 + if (!evlist) 867 + return -ENOMEM; 868 + 869 + cpus = perf_cpu_map__new("0"); 870 + if (!cpus) { 871 + evlist__delete(evlist); 872 + return -ENOMEM; 915 873 } 916 874 917 - if (resolve_metric_simple(data->ctx, &compound_list, table, 918 - pe->metric_name)) { 919 - expr_failure("Could not resolve metrics", pe); 920 - data->failures++; 921 - return TEST_FAIL; /* Don't tolerate errors due to severity */ 875 + perf_evlist__set_maps(&evlist->core, cpus, NULL); 876 + runtime_stat__init(&st); 877 + 878 + err = metricgroup__parse_groups_test(evlist, table, pe->metric_name, 879 + false, false, 880 + &metric_events); 881 + if (err) { 882 + if (!strcmp(pe->metric_name, "M1") || !strcmp(pe->metric_name, "M2") || 883 + !strcmp(pe->metric_name, "M3")) { 884 + (*failures)--; 885 + pr_debug("Expected broken metric %s skipping\n", pe->metric_name); 886 + err = 0; 887 + } 888 + goto out_err; 922 889 } 923 890 891 + err = evlist__alloc_stats(evlist, false); 892 + if (err) 893 + goto out_err; 924 894 /* 925 895 * Add all ids with a made up value. The value may trigger divide by 926 896 * zero when subtracted and so try to make them unique. 927 897 */ 928 898 k = 1; 929 - hashmap__for_each_entry(data->ctx->ids, cur, bkt) 930 - expr__add_id_val(data->ctx, strdup(cur->key), k++); 931 - 932 - hashmap__for_each_entry(data->ctx->ids, cur, bkt) { 933 - if (check_parse_cpu(cur->key, table == data->cpus_table, pe)) 934 - data->failures++; 899 + perf_stat__reset_shadow_stats(); 900 + evlist__for_each_entry(evlist, evsel) { 901 + perf_stat__update_shadow_stats(evsel, k, 0, &st); 902 + if (!strcmp(evsel->name, "duration_time")) 903 + update_stats(&walltime_nsecs_stats, k); 904 + k++; 935 905 } 906 + evlist__for_each_entry(evlist, evsel) { 907 + struct metric_event *me = metricgroup__lookup(&metric_events, evsel, false); 936 908 937 - list_for_each_entry_safe(metric, tmp, &compound_list, list) { 938 - expr__add_ref(data->ctx, &metric->metric_ref); 939 - free(metric); 940 - } 909 + if (me != NULL) { 910 + struct metric_expr *mexp; 941 911 942 - if (expr__parse(&result, data->ctx, pe->metric_expr)) { 943 - /* 944 - * Parsing failed, make numbers go from large to small which can 945 - * resolve divide by zero issues. 946 - */ 947 - k = 1024; 948 - hashmap__for_each_entry(data->ctx->ids, cur, bkt) 949 - expr__add_id_val(data->ctx, strdup(cur->key), k--); 950 - if (expr__parse(&result, data->ctx, pe->metric_expr)) { 951 - expr_failure("Parse failed", pe); 952 - data->failures++; 912 + list_for_each_entry (mexp, &me->head, nd) { 913 + if (strcmp(mexp->metric_name, pe->metric_name)) 914 + continue; 915 + pr_debug("Result %f\n", test_generic_metric(mexp, 0, &st)); 916 + err = 0; 917 + (*failures)--; 918 + goto out_err; 919 + } 953 920 } 954 921 } 955 - return 0; 922 + pr_debug("Didn't find parsed metric %s", pe->metric_name); 923 + err = 1; 924 + out_err: 925 + if (err) 926 + pr_debug("Broken metric %s\n", pe->metric_name); 927 + 928 + /* ... cleanup. */ 929 + metricgroup__rblist_exit(&metric_events); 930 + runtime_stat__exit(&st); 931 + evlist__free_stats(evlist); 932 + perf_cpu_map__put(cpus); 933 + evlist__delete(evlist); 934 + return err; 956 935 } 957 936 958 937 static int test__parsing(struct test_suite *test __maybe_unused, 959 938 int subtest __maybe_unused) 960 939 { 961 - struct test__parsing_data data = { 962 - .cpus_table = pmu_events_table__find(), 963 - .ctx = expr__ctx_new(), 964 - .failures = 0, 965 - }; 940 + int failures = 0; 966 941 967 - if (!data.ctx) { 968 - pr_debug("expr__ctx_new failed"); 969 - return TEST_FAIL; 970 - } 971 - pmu_for_each_core_event(test__parsing_callback, &data); 972 - pmu_for_each_sys_event(test__parsing_callback, &data); 942 + pmu_for_each_core_event(test__parsing_callback, &failures); 943 + pmu_for_each_sys_event(test__parsing_callback, &failures); 973 944 974 - expr__ctx_free(data.ctx); 975 - return data.failures == 0 ? TEST_OK : TEST_FAIL; 945 + return failures == 0 ? TEST_OK : TEST_FAIL; 976 946 } 977 947 978 948 struct test_metric {