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

perf tools: Cache counter names for raw samples on s390

Searching all event names is slower now that legacy names are
included. Add a cache to avoid long iterative searches. Note, the
cache isn't cleaned up and is as such a memory leak, however, globally
reachable leaks like this aren't treated as leaks by leak sanitizer.

Reported-by: Thomas Richter <tmricht@linux.ibm.com>
Closes: https://lore.kernel.org/linux-perf-users/09943f4f-516c-4b93-877c-e4a64ed61d38@linux.ibm.com/
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

authored by

Ian Rogers and committed by
Namhyung Kim
01bc5d2f 915c31f0

+50 -5
+50 -5
tools/perf/util/s390-sample-raw.c
··· 19 19 20 20 #include <sys/stat.h> 21 21 #include <linux/compiler.h> 22 + #include <linux/err.h> 22 23 #include <asm/byteorder.h> 23 24 24 25 #include "debug.h" 25 26 #include "session.h" 26 27 #include "evlist.h" 27 28 #include "color.h" 29 + #include "hashmap.h" 28 30 #include "sample-raw.h" 29 31 #include "s390-cpumcf-kernel.h" 30 32 #include "util/pmu.h" ··· 134 132 } 135 133 136 134 struct get_counter_name_data { 137 - int wanted; 138 - char *result; 135 + long wanted; 136 + const char *result; 139 137 }; 140 138 141 139 static int get_counter_name_callback(void *vdata, struct pmu_event_info *info) ··· 153 151 154 152 rc = sscanf(event_str, "event=%x", &event_nr); 155 153 if (rc == 1 && event_nr == data->wanted) { 156 - data->result = strdup(info->name); 154 + data->result = info->name; 157 155 return 1; /* Terminate the search. */ 158 156 } 159 157 return 0; 158 + } 159 + 160 + static size_t get_counter_name_hash_fn(long key, void *ctx __maybe_unused) 161 + { 162 + return key; 163 + } 164 + 165 + static bool get_counter_name_hashmap_equal_fn(long key1, long key2, void *ctx __maybe_unused) 166 + { 167 + return key1 == key2; 160 168 } 161 169 162 170 /* Scan the PMU and extract the logical name of a counter from the event. Input ··· 176 164 */ 177 165 static char *get_counter_name(int set, int nr, struct perf_pmu *pmu) 178 166 { 167 + static struct hashmap *cache; 168 + static struct perf_pmu *cache_pmu; 169 + long cache_key = get_counterset_start(set) + nr; 179 170 struct get_counter_name_data data = { 180 - .wanted = get_counterset_start(set) + nr, 171 + .wanted = cache_key, 181 172 .result = NULL, 182 173 }; 174 + char *result = NULL; 183 175 184 176 if (!pmu) 185 177 return NULL; 186 178 179 + if (cache_pmu == pmu && hashmap__find(cache, cache_key, &result)) 180 + return strdup(result); 181 + 187 182 perf_pmu__for_each_event(pmu, /*skip_duplicate_pmus=*/ true, 188 183 &data, get_counter_name_callback); 189 - return data.result; 184 + 185 + result = strdup(data.result ?: "<unknown>"); 186 + 187 + if (cache_pmu == NULL) { 188 + struct hashmap *tmp = hashmap__new(get_counter_name_hash_fn, 189 + get_counter_name_hashmap_equal_fn, 190 + /*ctx=*/NULL); 191 + 192 + if (!IS_ERR(tmp)) { 193 + cache = tmp; 194 + cache_pmu = pmu; 195 + } 196 + } 197 + 198 + if (cache_pmu == pmu && result) { 199 + char *old_value = NULL, *new_value = strdup(result); 200 + 201 + if (new_value) { 202 + hashmap__set(cache, cache_key, new_value, /*old_key=*/NULL, &old_value); 203 + /* 204 + * Free in case of a race, but resizing would be broken 205 + * in that case. 206 + */ 207 + free(old_value); 208 + } 209 + } 210 + return result; 190 211 } 191 212 192 213 static void s390_cpumcfdg_dump(struct perf_pmu *pmu, struct perf_sample *sample)