1480accbbSJin Yao // SPDX-License-Identifier: GPL-2.0 2480accbbSJin Yao /* 3480accbbSJin Yao * Compare and figure out the top N hottest streams 4480accbbSJin Yao * Copyright (c) 2020, Intel Corporation. 5480accbbSJin Yao * Author: Jin Yao 6480accbbSJin Yao */ 7480accbbSJin Yao 8480accbbSJin Yao #include <inttypes.h> 9480accbbSJin Yao #include <stdlib.h> 10480accbbSJin Yao #include <linux/zalloc.h> 11480accbbSJin Yao #include "debug.h" 12480accbbSJin Yao #include "hist.h" 13480accbbSJin Yao #include "sort.h" 14480accbbSJin Yao #include "stream.h" 15480accbbSJin Yao #include "evlist.h" 16480accbbSJin Yao 17480accbbSJin Yao static void evsel_streams__delete(struct evsel_streams *es, int nr_evsel) 18480accbbSJin Yao { 19480accbbSJin Yao for (int i = 0; i < nr_evsel; i++) 20480accbbSJin Yao zfree(&es[i].streams); 21480accbbSJin Yao 22480accbbSJin Yao free(es); 23480accbbSJin Yao } 24480accbbSJin Yao 25480accbbSJin Yao void evlist_streams__delete(struct evlist_streams *els) 26480accbbSJin Yao { 27480accbbSJin Yao evsel_streams__delete(els->ev_streams, els->nr_evsel); 28480accbbSJin Yao free(els); 29480accbbSJin Yao } 30480accbbSJin Yao 31480accbbSJin Yao static struct evlist_streams *evlist_streams__new(int nr_evsel, 32480accbbSJin Yao int nr_streams_max) 33480accbbSJin Yao { 34480accbbSJin Yao struct evlist_streams *els; 35480accbbSJin Yao struct evsel_streams *es; 36480accbbSJin Yao 37480accbbSJin Yao els = zalloc(sizeof(*els)); 38480accbbSJin Yao if (!els) 39480accbbSJin Yao return NULL; 40480accbbSJin Yao 41480accbbSJin Yao es = calloc(nr_evsel, sizeof(struct evsel_streams)); 42480accbbSJin Yao if (!es) { 43480accbbSJin Yao free(els); 44480accbbSJin Yao return NULL; 45480accbbSJin Yao } 46480accbbSJin Yao 47480accbbSJin Yao for (int i = 0; i < nr_evsel; i++) { 48480accbbSJin Yao struct evsel_streams *s = &es[i]; 49480accbbSJin Yao 50480accbbSJin Yao s->streams = calloc(nr_streams_max, sizeof(struct stream)); 51480accbbSJin Yao if (!s->streams) 52480accbbSJin Yao goto err; 53480accbbSJin Yao 54480accbbSJin Yao s->nr_streams_max = nr_streams_max; 55480accbbSJin Yao s->evsel_idx = -1; 56480accbbSJin Yao } 57480accbbSJin Yao 58480accbbSJin Yao els->ev_streams = es; 59480accbbSJin Yao els->nr_evsel = nr_evsel; 60480accbbSJin Yao return els; 61480accbbSJin Yao 62480accbbSJin Yao err: 63480accbbSJin Yao evsel_streams__delete(es, nr_evsel); 64480accbbSJin Yao return NULL; 65480accbbSJin Yao } 66480accbbSJin Yao 67480accbbSJin Yao /* 68480accbbSJin Yao * The cnodes with high hit number are hot callchains. 69480accbbSJin Yao */ 70480accbbSJin Yao static void evsel_streams__set_hot_cnode(struct evsel_streams *es, 71480accbbSJin Yao struct callchain_node *cnode) 72480accbbSJin Yao { 73480accbbSJin Yao int i, idx = 0; 74480accbbSJin Yao u64 hit; 75480accbbSJin Yao 76480accbbSJin Yao if (es->nr_streams < es->nr_streams_max) { 77480accbbSJin Yao i = es->nr_streams; 78480accbbSJin Yao es->streams[i].cnode = cnode; 79480accbbSJin Yao es->nr_streams++; 80480accbbSJin Yao return; 81480accbbSJin Yao } 82480accbbSJin Yao 83480accbbSJin Yao /* 84480accbbSJin Yao * Considering a few number of hot streams, only use simple 85480accbbSJin Yao * way to find the cnode with smallest hit number and replace. 86480accbbSJin Yao */ 87480accbbSJin Yao hit = (es->streams[0].cnode)->hit; 88480accbbSJin Yao for (i = 1; i < es->nr_streams; i++) { 89480accbbSJin Yao if ((es->streams[i].cnode)->hit < hit) { 90480accbbSJin Yao hit = (es->streams[i].cnode)->hit; 91480accbbSJin Yao idx = i; 92480accbbSJin Yao } 93480accbbSJin Yao } 94480accbbSJin Yao 95480accbbSJin Yao if (cnode->hit > hit) 96480accbbSJin Yao es->streams[idx].cnode = cnode; 97480accbbSJin Yao } 98480accbbSJin Yao 99480accbbSJin Yao static void update_hot_callchain(struct hist_entry *he, 100480accbbSJin Yao struct evsel_streams *es) 101480accbbSJin Yao { 102480accbbSJin Yao struct rb_root *root = &he->sorted_chain; 103480accbbSJin Yao struct rb_node *rb_node = rb_first(root); 104480accbbSJin Yao struct callchain_node *cnode; 105480accbbSJin Yao 106480accbbSJin Yao while (rb_node) { 107480accbbSJin Yao cnode = rb_entry(rb_node, struct callchain_node, rb_node); 108480accbbSJin Yao evsel_streams__set_hot_cnode(es, cnode); 109480accbbSJin Yao rb_node = rb_next(rb_node); 110480accbbSJin Yao } 111480accbbSJin Yao } 112480accbbSJin Yao 113480accbbSJin Yao static void init_hot_callchain(struct hists *hists, struct evsel_streams *es) 114480accbbSJin Yao { 115480accbbSJin Yao struct rb_node *next = rb_first_cached(&hists->entries); 116480accbbSJin Yao 117480accbbSJin Yao while (next) { 118480accbbSJin Yao struct hist_entry *he; 119480accbbSJin Yao 120480accbbSJin Yao he = rb_entry(next, struct hist_entry, rb_node); 121480accbbSJin Yao update_hot_callchain(he, es); 122480accbbSJin Yao next = rb_next(&he->rb_node); 123480accbbSJin Yao } 124*28904f4dSJin Yao 125*28904f4dSJin Yao es->streams_hits = callchain_total_hits(hists); 126480accbbSJin Yao } 127480accbbSJin Yao 128480accbbSJin Yao static int evlist__init_callchain_streams(struct evlist *evlist, 129480accbbSJin Yao struct evlist_streams *els) 130480accbbSJin Yao { 131480accbbSJin Yao struct evsel_streams *es = els->ev_streams; 132480accbbSJin Yao struct evsel *pos; 133480accbbSJin Yao int i = 0; 134480accbbSJin Yao 135480accbbSJin Yao BUG_ON(els->nr_evsel < evlist->core.nr_entries); 136480accbbSJin Yao 137480accbbSJin Yao evlist__for_each_entry(evlist, pos) { 138480accbbSJin Yao struct hists *hists = evsel__hists(pos); 139480accbbSJin Yao 140480accbbSJin Yao hists__output_resort(hists, NULL); 141480accbbSJin Yao init_hot_callchain(hists, &es[i]); 142480accbbSJin Yao es[i].evsel_idx = pos->idx; 143480accbbSJin Yao i++; 144480accbbSJin Yao } 145480accbbSJin Yao 146480accbbSJin Yao return 0; 147480accbbSJin Yao } 148480accbbSJin Yao 149480accbbSJin Yao struct evlist_streams *evlist__create_streams(struct evlist *evlist, 150480accbbSJin Yao int nr_streams_max) 151480accbbSJin Yao { 152480accbbSJin Yao int nr_evsel = evlist->core.nr_entries, ret = -1; 153480accbbSJin Yao struct evlist_streams *els = evlist_streams__new(nr_evsel, 154480accbbSJin Yao nr_streams_max); 155480accbbSJin Yao 156480accbbSJin Yao if (!els) 157480accbbSJin Yao return NULL; 158480accbbSJin Yao 159480accbbSJin Yao ret = evlist__init_callchain_streams(evlist, els); 160480accbbSJin Yao if (ret) { 161480accbbSJin Yao evlist_streams__delete(els); 162480accbbSJin Yao return NULL; 163480accbbSJin Yao } 164480accbbSJin Yao 165480accbbSJin Yao return els; 166480accbbSJin Yao } 167dd1d8418SJin Yao 168dd1d8418SJin Yao struct evsel_streams *evsel_streams__entry(struct evlist_streams *els, 169dd1d8418SJin Yao int evsel_idx) 170dd1d8418SJin Yao { 171dd1d8418SJin Yao struct evsel_streams *es = els->ev_streams; 172dd1d8418SJin Yao 173dd1d8418SJin Yao for (int i = 0; i < els->nr_evsel; i++) { 174dd1d8418SJin Yao if (es[i].evsel_idx == evsel_idx) 175dd1d8418SJin Yao return &es[i]; 176dd1d8418SJin Yao } 177dd1d8418SJin Yao 178dd1d8418SJin Yao return NULL; 179dd1d8418SJin Yao } 180fa79aa64SJin Yao 181fa79aa64SJin Yao static struct stream *stream__callchain_match(struct stream *base_stream, 182fa79aa64SJin Yao struct evsel_streams *es_pair) 183fa79aa64SJin Yao { 184fa79aa64SJin Yao for (int i = 0; i < es_pair->nr_streams; i++) { 185fa79aa64SJin Yao struct stream *pair_stream = &es_pair->streams[i]; 186fa79aa64SJin Yao 187fa79aa64SJin Yao if (callchain_cnode_matched(base_stream->cnode, 188fa79aa64SJin Yao pair_stream->cnode)) { 189fa79aa64SJin Yao return pair_stream; 190fa79aa64SJin Yao } 191fa79aa64SJin Yao } 192fa79aa64SJin Yao 193fa79aa64SJin Yao return NULL; 194fa79aa64SJin Yao } 195fa79aa64SJin Yao 196fa79aa64SJin Yao static struct stream *stream__match(struct stream *base_stream, 197fa79aa64SJin Yao struct evsel_streams *es_pair) 198fa79aa64SJin Yao { 199fa79aa64SJin Yao return stream__callchain_match(base_stream, es_pair); 200fa79aa64SJin Yao } 201fa79aa64SJin Yao 202fa79aa64SJin Yao static void stream__link(struct stream *base_stream, struct stream *pair_stream) 203fa79aa64SJin Yao { 204fa79aa64SJin Yao base_stream->pair_cnode = pair_stream->cnode; 205fa79aa64SJin Yao pair_stream->pair_cnode = base_stream->cnode; 206fa79aa64SJin Yao } 207fa79aa64SJin Yao 208fa79aa64SJin Yao void evsel_streams__match(struct evsel_streams *es_base, 209fa79aa64SJin Yao struct evsel_streams *es_pair) 210fa79aa64SJin Yao { 211fa79aa64SJin Yao for (int i = 0; i < es_base->nr_streams; i++) { 212fa79aa64SJin Yao struct stream *base_stream = &es_base->streams[i]; 213fa79aa64SJin Yao struct stream *pair_stream; 214fa79aa64SJin Yao 215fa79aa64SJin Yao pair_stream = stream__match(base_stream, es_pair); 216fa79aa64SJin Yao if (pair_stream) 217fa79aa64SJin Yao stream__link(base_stream, pair_stream); 218fa79aa64SJin Yao } 219fa79aa64SJin Yao } 220