// SPDX-License-Identifier: GPL-2.01#include <string.h>2#include "../../../util/evlist.h"3#include "../../../util/evsel.h"4#include "topdown.h"5#include "evsel.h"67int arch_evlist__cmp(const struct evsel *lhs, const struct evsel *rhs)8{9/*10* Currently the following topdown events sequence are supported to11* move and regroup correctly.12*13* a. all events in a group14* perf stat -e "{instructions,topdown-retiring,slots}" -C0 sleep 115* WARNING: events were regrouped to match PMUs16* Performance counter stats for 'CPU(s) 0':17* 15,066,240 slots18* 1,899,760 instructions19* 2,126,998 topdown-retiring20* b. all events not in a group21* perf stat -e "instructions,topdown-retiring,slots" -C0 sleep 122* WARNING: events were regrouped to match PMUs23* Performance counter stats for 'CPU(s) 0':24* 2,045,561 instructions25* 17,108,370 slots26* 2,281,116 topdown-retiring27* c. slots event in a group but topdown metrics events outside the group28* perf stat -e "{instructions,slots},topdown-retiring" -C0 sleep 129* WARNING: events were regrouped to match PMUs30* Performance counter stats for 'CPU(s) 0':31* 20,323,878 slots32* 2,634,884 instructions33* 3,028,656 topdown-retiring34* d. slots event and topdown metrics events in two groups35* perf stat -e "{instructions,slots},{topdown-retiring}" -C0 sleep 136* WARNING: events were regrouped to match PMUs37* Performance counter stats for 'CPU(s) 0':38* 26,319,024 slots39* 2,427,791 instructions40* 2,683,508 topdown-retiring41* e. slots event and metrics event are not in a group and not adjacent42* perf stat -e "{instructions,slots},cycles,topdown-retiring" -C0 sleep 143* WARNING: events were regrouped to match PMUs44* 68,433,522 slots45* 8,856,102 topdown-retiring46* 7,791,494 instructions47* 11,469,513 cycles48*/49if (topdown_sys_has_perf_metrics() &&50(arch_evsel__must_be_in_group(lhs) || arch_evsel__must_be_in_group(rhs))) {51/* Ensure the topdown slots comes first. */52if (arch_is_topdown_slots(lhs))53return -1;54if (arch_is_topdown_slots(rhs))55return 1;5657/*58* Move topdown metrics events forward only when topdown metrics59* events are not in same group with previous slots event. If60* topdown metrics events are already in same group with slots61* event, do nothing.62*/63if (lhs->core.leader != rhs->core.leader) {64bool lhs_topdown = arch_is_topdown_metrics(lhs);65bool rhs_topdown = arch_is_topdown_metrics(rhs);6667if (lhs_topdown && !rhs_topdown)68return -1;69if (!lhs_topdown && rhs_topdown)70return 1;71}72}7374/* Retire latency event should not be group leader*/75if (lhs->retire_lat && !rhs->retire_lat)76return 1;77if (!lhs->retire_lat && rhs->retire_lat)78return -1;7980/* Default ordering by insertion index. */81return lhs->core.idx - rhs->core.idx;82}8384int arch_evlist__add_required_events(struct list_head *list)85{86struct evsel *pos, *metric_event = NULL;87int idx = 0;8889if (!topdown_sys_has_perf_metrics())90return 0;9192list_for_each_entry(pos, list, core.node) {93if (arch_is_topdown_slots(pos)) {94/* Slots event already present, nothing to do. */95return 0;96}97if (metric_event == NULL && arch_is_topdown_metrics(pos))98metric_event = pos;99idx++;100}101if (metric_event == NULL) {102/* No topdown metric events, nothing to do. */103return 0;104}105return topdown_insert_slots_event(list, idx + 1, metric_event);106}107108109