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

perf tools: Add coresight etm PMU record capabilities

Coresight ETMs are IP blocks used to perform HW assisted tracing on a
CPU core. This patch introduce the required auxiliary API functions
allowing the perf core to interact with a tracer.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: linux-arm-kernel@lists.infradead.org
Link: http://lkml.kernel.org/r/1474041004-13956-4-git-send-email-mathieu.poirier@linaro.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Mathieu Poirier and committed by
Arnaldo Carvalho de Melo
a818c563 7e21b0d5

+720 -2
+4
MAINTAINERS
··· 1124 1124 F: Documentation/devicetree/bindings/arm/coresight.txt 1125 1125 F: Documentation/ABI/testing/sysfs-bus-coresight-devices-* 1126 1126 F: tools/perf/arch/arm/util/pmu.c 1127 + F: tools/perf/arch/arm/util/auxtrace.c 1128 + F: tools/perf/arch/arm/util/cs-etm.c 1129 + F: tools/perf/arch/arm/util/cs-etm.h 1130 + F: tools/perf/util/cs-etm.h 1127 1131 1128 1132 ARM/CORGI MACHINE SUPPORT 1129 1133 M: Richard Purdie <rpurdie@rpsys.net>
+1 -1
tools/perf/arch/arm/util/Build
··· 3 3 libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o 4 4 libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o 5 5 6 - libperf-$(CONFIG_AUXTRACE) += pmu.o 6 + libperf-$(CONFIG_AUXTRACE) += pmu.o auxtrace.o cs-etm.o
+54
tools/perf/arch/arm/util/auxtrace.c
··· 1 + /* 2 + * Copyright(C) 2015 Linaro Limited. All rights reserved. 3 + * Author: Mathieu Poirier <mathieu.poirier@linaro.org> 4 + * 5 + * This program is free software; you can redistribute it and/or modify it 6 + * under the terms of the GNU General Public License version 2 as published by 7 + * the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, but WITHOUT 10 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 + * more details. 13 + * 14 + * You should have received a copy of the GNU General Public License along with 15 + * this program. If not, see <http://www.gnu.org/licenses/>. 16 + */ 17 + 18 + #include <stdbool.h> 19 + #include <linux/coresight-pmu.h> 20 + 21 + #include "../../util/auxtrace.h" 22 + #include "../../util/evlist.h" 23 + #include "../../util/pmu.h" 24 + #include "cs-etm.h" 25 + 26 + struct auxtrace_record 27 + *auxtrace_record__init(struct perf_evlist *evlist, int *err) 28 + { 29 + struct perf_pmu *cs_etm_pmu; 30 + struct perf_evsel *evsel; 31 + bool found_etm = false; 32 + 33 + cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME); 34 + 35 + if (evlist) { 36 + evlist__for_each_entry(evlist, evsel) { 37 + if (cs_etm_pmu && 38 + evsel->attr.type == cs_etm_pmu->type) 39 + found_etm = true; 40 + } 41 + } 42 + 43 + if (found_etm) 44 + return cs_etm_record_init(err); 45 + 46 + /* 47 + * Clear 'err' even if we haven't found a cs_etm event - that way perf 48 + * record can still be used even if tracers aren't present. The NULL 49 + * return value will take care of telling the infrastructure HW tracing 50 + * isn't available. 51 + */ 52 + *err = 0; 53 + return NULL; 54 + }
+559
tools/perf/arch/arm/util/cs-etm.c
··· 1 + /* 2 + * Copyright(C) 2015 Linaro Limited. All rights reserved. 3 + * Author: Mathieu Poirier <mathieu.poirier@linaro.org> 4 + * 5 + * This program is free software; you can redistribute it and/or modify it 6 + * under the terms of the GNU General Public License version 2 as published by 7 + * the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, but WITHOUT 10 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 + * more details. 13 + * 14 + * You should have received a copy of the GNU General Public License along with 15 + * this program. If not, see <http://www.gnu.org/licenses/>. 16 + */ 17 + 18 + #include <api/fs/fs.h> 19 + #include <linux/bitops.h> 20 + #include <linux/coresight-pmu.h> 21 + #include <linux/kernel.h> 22 + #include <linux/log2.h> 23 + #include <linux/types.h> 24 + 25 + #include "cs-etm.h" 26 + #include "../../perf.h" 27 + #include "../../util/auxtrace.h" 28 + #include "../../util/cpumap.h" 29 + #include "../../util/evlist.h" 30 + #include "../../util/pmu.h" 31 + #include "../../util/thread_map.h" 32 + #include "../../util/cs-etm.h" 33 + 34 + #include <stdlib.h> 35 + 36 + struct cs_etm_recording { 37 + struct auxtrace_record itr; 38 + struct perf_pmu *cs_etm_pmu; 39 + struct perf_evlist *evlist; 40 + bool snapshot_mode; 41 + size_t snapshot_size; 42 + }; 43 + 44 + static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu); 45 + 46 + static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr, 47 + struct record_opts *opts, 48 + const char *str) 49 + { 50 + struct cs_etm_recording *ptr = 51 + container_of(itr, struct cs_etm_recording, itr); 52 + unsigned long long snapshot_size = 0; 53 + char *endptr; 54 + 55 + if (str) { 56 + snapshot_size = strtoull(str, &endptr, 0); 57 + if (*endptr || snapshot_size > SIZE_MAX) 58 + return -1; 59 + } 60 + 61 + opts->auxtrace_snapshot_mode = true; 62 + opts->auxtrace_snapshot_size = snapshot_size; 63 + ptr->snapshot_size = snapshot_size; 64 + 65 + return 0; 66 + } 67 + 68 + static int cs_etm_recording_options(struct auxtrace_record *itr, 69 + struct perf_evlist *evlist, 70 + struct record_opts *opts) 71 + { 72 + struct cs_etm_recording *ptr = 73 + container_of(itr, struct cs_etm_recording, itr); 74 + struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 75 + struct perf_evsel *evsel, *cs_etm_evsel = NULL; 76 + const struct cpu_map *cpus = evlist->cpus; 77 + bool privileged = (geteuid() == 0 || perf_event_paranoid() < 0); 78 + 79 + ptr->evlist = evlist; 80 + ptr->snapshot_mode = opts->auxtrace_snapshot_mode; 81 + 82 + evlist__for_each_entry(evlist, evsel) { 83 + if (evsel->attr.type == cs_etm_pmu->type) { 84 + if (cs_etm_evsel) { 85 + pr_err("There may be only one %s event\n", 86 + CORESIGHT_ETM_PMU_NAME); 87 + return -EINVAL; 88 + } 89 + evsel->attr.freq = 0; 90 + evsel->attr.sample_period = 1; 91 + cs_etm_evsel = evsel; 92 + opts->full_auxtrace = true; 93 + } 94 + } 95 + 96 + /* no need to continue if at least one event of interest was found */ 97 + if (!cs_etm_evsel) 98 + return 0; 99 + 100 + if (opts->use_clockid) { 101 + pr_err("Cannot use clockid (-k option) with %s\n", 102 + CORESIGHT_ETM_PMU_NAME); 103 + return -EINVAL; 104 + } 105 + 106 + /* we are in snapshot mode */ 107 + if (opts->auxtrace_snapshot_mode) { 108 + /* 109 + * No size were given to '-S' or '-m,', so go with 110 + * the default 111 + */ 112 + if (!opts->auxtrace_snapshot_size && 113 + !opts->auxtrace_mmap_pages) { 114 + if (privileged) { 115 + opts->auxtrace_mmap_pages = MiB(4) / page_size; 116 + } else { 117 + opts->auxtrace_mmap_pages = 118 + KiB(128) / page_size; 119 + if (opts->mmap_pages == UINT_MAX) 120 + opts->mmap_pages = KiB(256) / page_size; 121 + } 122 + } else if (!opts->auxtrace_mmap_pages && !privileged && 123 + opts->mmap_pages == UINT_MAX) { 124 + opts->mmap_pages = KiB(256) / page_size; 125 + } 126 + 127 + /* 128 + * '-m,xyz' was specified but no snapshot size, so make the 129 + * snapshot size as big as the auxtrace mmap area. 130 + */ 131 + if (!opts->auxtrace_snapshot_size) { 132 + opts->auxtrace_snapshot_size = 133 + opts->auxtrace_mmap_pages * (size_t)page_size; 134 + } 135 + 136 + /* 137 + * -Sxyz was specified but no auxtrace mmap area, so make the 138 + * auxtrace mmap area big enough to fit the requested snapshot 139 + * size. 140 + */ 141 + if (!opts->auxtrace_mmap_pages) { 142 + size_t sz = opts->auxtrace_snapshot_size; 143 + 144 + sz = round_up(sz, page_size) / page_size; 145 + opts->auxtrace_mmap_pages = roundup_pow_of_two(sz); 146 + } 147 + 148 + /* Snapshost size can't be bigger than the auxtrace area */ 149 + if (opts->auxtrace_snapshot_size > 150 + opts->auxtrace_mmap_pages * (size_t)page_size) { 151 + pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n", 152 + opts->auxtrace_snapshot_size, 153 + opts->auxtrace_mmap_pages * (size_t)page_size); 154 + return -EINVAL; 155 + } 156 + 157 + /* Something went wrong somewhere - this shouldn't happen */ 158 + if (!opts->auxtrace_snapshot_size || 159 + !opts->auxtrace_mmap_pages) { 160 + pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n"); 161 + return -EINVAL; 162 + } 163 + } 164 + 165 + /* We are in full trace mode but '-m,xyz' wasn't specified */ 166 + if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) { 167 + if (privileged) { 168 + opts->auxtrace_mmap_pages = MiB(4) / page_size; 169 + } else { 170 + opts->auxtrace_mmap_pages = KiB(128) / page_size; 171 + if (opts->mmap_pages == UINT_MAX) 172 + opts->mmap_pages = KiB(256) / page_size; 173 + } 174 + 175 + } 176 + 177 + /* Validate auxtrace_mmap_pages provided by user */ 178 + if (opts->auxtrace_mmap_pages) { 179 + unsigned int max_page = (KiB(128) / page_size); 180 + size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size; 181 + 182 + if (!privileged && 183 + opts->auxtrace_mmap_pages > max_page) { 184 + opts->auxtrace_mmap_pages = max_page; 185 + pr_err("auxtrace too big, truncating to %d\n", 186 + max_page); 187 + } 188 + 189 + if (!is_power_of_2(sz)) { 190 + pr_err("Invalid mmap size for %s: must be a power of 2\n", 191 + CORESIGHT_ETM_PMU_NAME); 192 + return -EINVAL; 193 + } 194 + } 195 + 196 + if (opts->auxtrace_snapshot_mode) 197 + pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME, 198 + opts->auxtrace_snapshot_size); 199 + 200 + if (cs_etm_evsel) { 201 + /* 202 + * To obtain the auxtrace buffer file descriptor, the auxtrace 203 + * event must come first. 204 + */ 205 + perf_evlist__to_front(evlist, cs_etm_evsel); 206 + /* 207 + * In the case of per-cpu mmaps, we need the CPU on the 208 + * AUX event. 209 + */ 210 + if (!cpu_map__empty(cpus)) 211 + perf_evsel__set_sample_bit(cs_etm_evsel, CPU); 212 + } 213 + 214 + /* Add dummy event to keep tracking */ 215 + if (opts->full_auxtrace) { 216 + struct perf_evsel *tracking_evsel; 217 + int err; 218 + 219 + err = parse_events(evlist, "dummy:u", NULL); 220 + if (err) 221 + return err; 222 + 223 + tracking_evsel = perf_evlist__last(evlist); 224 + perf_evlist__set_tracking_event(evlist, tracking_evsel); 225 + 226 + tracking_evsel->attr.freq = 0; 227 + tracking_evsel->attr.sample_period = 1; 228 + 229 + /* In per-cpu case, always need the time of mmap events etc */ 230 + if (!cpu_map__empty(cpus)) 231 + perf_evsel__set_sample_bit(tracking_evsel, TIME); 232 + } 233 + 234 + return 0; 235 + } 236 + 237 + static u64 cs_etm_get_config(struct auxtrace_record *itr) 238 + { 239 + u64 config = 0; 240 + struct cs_etm_recording *ptr = 241 + container_of(itr, struct cs_etm_recording, itr); 242 + struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 243 + struct perf_evlist *evlist = ptr->evlist; 244 + struct perf_evsel *evsel; 245 + 246 + evlist__for_each_entry(evlist, evsel) { 247 + if (evsel->attr.type == cs_etm_pmu->type) { 248 + /* 249 + * Variable perf_event_attr::config is assigned to 250 + * ETMv3/PTM. The bit fields have been made to match 251 + * the ETMv3.5 ETRMCR register specification. See the 252 + * PMU_FORMAT_ATTR() declarations in 253 + * drivers/hwtracing/coresight/coresight-perf.c for 254 + * details. 255 + */ 256 + config = evsel->attr.config; 257 + break; 258 + } 259 + } 260 + 261 + return config; 262 + } 263 + 264 + static size_t 265 + cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, 266 + struct perf_evlist *evlist __maybe_unused) 267 + { 268 + int i; 269 + int etmv3 = 0, etmv4 = 0; 270 + const struct cpu_map *cpus = evlist->cpus; 271 + 272 + /* cpu map is not empty, we have specific CPUs to work with */ 273 + if (!cpu_map__empty(cpus)) { 274 + for (i = 0; i < cpu_map__nr(cpus); i++) { 275 + if (cs_etm_is_etmv4(itr, cpus->map[i])) 276 + etmv4++; 277 + else 278 + etmv3++; 279 + } 280 + } else { 281 + /* get configuration for all CPUs in the system */ 282 + for (i = 0; i < cpu__max_cpu(); i++) { 283 + if (cs_etm_is_etmv4(itr, i)) 284 + etmv4++; 285 + else 286 + etmv3++; 287 + } 288 + } 289 + 290 + return (CS_ETM_HEADER_SIZE + 291 + (etmv4 * CS_ETMV4_PRIV_SIZE) + 292 + (etmv3 * CS_ETMV3_PRIV_SIZE)); 293 + } 294 + 295 + static const char *metadata_etmv3_ro[CS_ETM_PRIV_MAX] = { 296 + [CS_ETM_ETMCCER] = "mgmt/etmccer", 297 + [CS_ETM_ETMIDR] = "mgmt/etmidr", 298 + }; 299 + 300 + static const char *metadata_etmv4_ro[CS_ETMV4_PRIV_MAX] = { 301 + [CS_ETMV4_TRCIDR0] = "trcidr/trcidr0", 302 + [CS_ETMV4_TRCIDR1] = "trcidr/trcidr1", 303 + [CS_ETMV4_TRCIDR2] = "trcidr/trcidr2", 304 + [CS_ETMV4_TRCIDR8] = "trcidr/trcidr8", 305 + [CS_ETMV4_TRCAUTHSTATUS] = "mgmt/trcauthstatus", 306 + }; 307 + 308 + static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu) 309 + { 310 + bool ret = false; 311 + char path[PATH_MAX]; 312 + int scan; 313 + unsigned int val; 314 + struct cs_etm_recording *ptr = 315 + container_of(itr, struct cs_etm_recording, itr); 316 + struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 317 + 318 + /* Take any of the RO files for ETMv4 and see if it present */ 319 + snprintf(path, PATH_MAX, "cpu%d/%s", 320 + cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 321 + scan = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); 322 + 323 + /* The file was read successfully, we have a winner */ 324 + if (scan == 1) 325 + ret = true; 326 + 327 + return ret; 328 + } 329 + 330 + static int cs_etm_get_ro(struct perf_pmu *pmu, int cpu, const char *path) 331 + { 332 + char pmu_path[PATH_MAX]; 333 + int scan; 334 + unsigned int val = 0; 335 + 336 + /* Get RO metadata from sysfs */ 337 + snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); 338 + 339 + scan = perf_pmu__scan_file(pmu, pmu_path, "%x", &val); 340 + if (scan != 1) 341 + pr_err("%s: error reading: %s\n", __func__, pmu_path); 342 + 343 + return val; 344 + } 345 + 346 + static void cs_etm_get_metadata(int cpu, u32 *offset, 347 + struct auxtrace_record *itr, 348 + struct auxtrace_info_event *info) 349 + { 350 + u32 increment; 351 + u64 magic; 352 + struct cs_etm_recording *ptr = 353 + container_of(itr, struct cs_etm_recording, itr); 354 + struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 355 + 356 + /* first see what kind of tracer this cpu is affined to */ 357 + if (cs_etm_is_etmv4(itr, cpu)) { 358 + magic = __perf_cs_etmv4_magic; 359 + /* Get trace configuration register */ 360 + info->priv[*offset + CS_ETMV4_TRCCONFIGR] = 361 + cs_etm_get_config(itr); 362 + /* Get traceID from the framework */ 363 + info->priv[*offset + CS_ETMV4_TRCTRACEIDR] = 364 + coresight_get_trace_id(cpu); 365 + /* Get read-only information from sysFS */ 366 + info->priv[*offset + CS_ETMV4_TRCIDR0] = 367 + cs_etm_get_ro(cs_etm_pmu, cpu, 368 + metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 369 + info->priv[*offset + CS_ETMV4_TRCIDR1] = 370 + cs_etm_get_ro(cs_etm_pmu, cpu, 371 + metadata_etmv4_ro[CS_ETMV4_TRCIDR1]); 372 + info->priv[*offset + CS_ETMV4_TRCIDR2] = 373 + cs_etm_get_ro(cs_etm_pmu, cpu, 374 + metadata_etmv4_ro[CS_ETMV4_TRCIDR2]); 375 + info->priv[*offset + CS_ETMV4_TRCIDR8] = 376 + cs_etm_get_ro(cs_etm_pmu, cpu, 377 + metadata_etmv4_ro[CS_ETMV4_TRCIDR8]); 378 + info->priv[*offset + CS_ETMV4_TRCAUTHSTATUS] = 379 + cs_etm_get_ro(cs_etm_pmu, cpu, 380 + metadata_etmv4_ro 381 + [CS_ETMV4_TRCAUTHSTATUS]); 382 + 383 + /* How much space was used */ 384 + increment = CS_ETMV4_PRIV_MAX; 385 + } else { 386 + magic = __perf_cs_etmv3_magic; 387 + /* Get configuration register */ 388 + info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr); 389 + /* Get traceID from the framework */ 390 + info->priv[*offset + CS_ETM_ETMTRACEIDR] = 391 + coresight_get_trace_id(cpu); 392 + /* Get read-only information from sysFS */ 393 + info->priv[*offset + CS_ETM_ETMCCER] = 394 + cs_etm_get_ro(cs_etm_pmu, cpu, 395 + metadata_etmv3_ro[CS_ETM_ETMCCER]); 396 + info->priv[*offset + CS_ETM_ETMIDR] = 397 + cs_etm_get_ro(cs_etm_pmu, cpu, 398 + metadata_etmv3_ro[CS_ETM_ETMIDR]); 399 + 400 + /* How much space was used */ 401 + increment = CS_ETM_PRIV_MAX; 402 + } 403 + 404 + /* Build generic header portion */ 405 + info->priv[*offset + CS_ETM_MAGIC] = magic; 406 + info->priv[*offset + CS_ETM_CPU] = cpu; 407 + /* Where the next CPU entry should start from */ 408 + *offset += increment; 409 + } 410 + 411 + static int cs_etm_info_fill(struct auxtrace_record *itr, 412 + struct perf_session *session, 413 + struct auxtrace_info_event *info, 414 + size_t priv_size) 415 + { 416 + int i; 417 + u32 offset; 418 + u64 nr_cpu, type; 419 + const struct cpu_map *cpus = session->evlist->cpus; 420 + struct cs_etm_recording *ptr = 421 + container_of(itr, struct cs_etm_recording, itr); 422 + struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 423 + 424 + if (priv_size != cs_etm_info_priv_size(itr, session->evlist)) 425 + return -EINVAL; 426 + 427 + if (!session->evlist->nr_mmaps) 428 + return -EINVAL; 429 + 430 + /* If the cpu_map is empty all CPUs are involved */ 431 + nr_cpu = cpu_map__empty(cpus) ? cpu__max_cpu() : cpu_map__nr(cpus); 432 + /* Get PMU type as dynamically assigned by the core */ 433 + type = cs_etm_pmu->type; 434 + 435 + /* First fill out the session header */ 436 + info->type = PERF_AUXTRACE_CS_ETM; 437 + info->priv[CS_HEADER_VERSION_0] = 0; 438 + info->priv[CS_PMU_TYPE_CPUS] = type << 32; 439 + info->priv[CS_PMU_TYPE_CPUS] |= nr_cpu; 440 + info->priv[CS_ETM_SNAPSHOT] = ptr->snapshot_mode; 441 + 442 + offset = CS_ETM_SNAPSHOT + 1; 443 + 444 + /* cpu map is not empty, we have specific CPUs to work with */ 445 + if (!cpu_map__empty(cpus)) { 446 + for (i = 0; i < cpu_map__nr(cpus) && offset < priv_size; i++) 447 + cs_etm_get_metadata(cpus->map[i], &offset, itr, info); 448 + } else { 449 + /* get configuration for all CPUs in the system */ 450 + for (i = 0; i < cpu__max_cpu(); i++) 451 + cs_etm_get_metadata(i, &offset, itr, info); 452 + } 453 + 454 + return 0; 455 + } 456 + 457 + static int cs_etm_find_snapshot(struct auxtrace_record *itr __maybe_unused, 458 + int idx, struct auxtrace_mmap *mm, 459 + unsigned char *data __maybe_unused, 460 + u64 *head, u64 *old) 461 + { 462 + pr_debug3("%s: mmap index %d old head %zu new head %zu size %zu\n", 463 + __func__, idx, (size_t)*old, (size_t)*head, mm->len); 464 + 465 + *old = *head; 466 + *head += mm->len; 467 + 468 + return 0; 469 + } 470 + 471 + static int cs_etm_snapshot_start(struct auxtrace_record *itr) 472 + { 473 + struct cs_etm_recording *ptr = 474 + container_of(itr, struct cs_etm_recording, itr); 475 + struct perf_evsel *evsel; 476 + 477 + evlist__for_each_entry(ptr->evlist, evsel) { 478 + if (evsel->attr.type == ptr->cs_etm_pmu->type) 479 + return perf_evsel__disable(evsel); 480 + } 481 + return -EINVAL; 482 + } 483 + 484 + static int cs_etm_snapshot_finish(struct auxtrace_record *itr) 485 + { 486 + struct cs_etm_recording *ptr = 487 + container_of(itr, struct cs_etm_recording, itr); 488 + struct perf_evsel *evsel; 489 + 490 + evlist__for_each_entry(ptr->evlist, evsel) { 491 + if (evsel->attr.type == ptr->cs_etm_pmu->type) 492 + return perf_evsel__enable(evsel); 493 + } 494 + return -EINVAL; 495 + } 496 + 497 + static u64 cs_etm_reference(struct auxtrace_record *itr __maybe_unused) 498 + { 499 + return (((u64) rand() << 0) & 0x00000000FFFFFFFFull) | 500 + (((u64) rand() << 32) & 0xFFFFFFFF00000000ull); 501 + } 502 + 503 + static void cs_etm_recording_free(struct auxtrace_record *itr) 504 + { 505 + struct cs_etm_recording *ptr = 506 + container_of(itr, struct cs_etm_recording, itr); 507 + free(ptr); 508 + } 509 + 510 + static int cs_etm_read_finish(struct auxtrace_record *itr, int idx) 511 + { 512 + struct cs_etm_recording *ptr = 513 + container_of(itr, struct cs_etm_recording, itr); 514 + struct perf_evsel *evsel; 515 + 516 + evlist__for_each_entry(ptr->evlist, evsel) { 517 + if (evsel->attr.type == ptr->cs_etm_pmu->type) 518 + return perf_evlist__enable_event_idx(ptr->evlist, 519 + evsel, idx); 520 + } 521 + 522 + return -EINVAL; 523 + } 524 + 525 + struct auxtrace_record *cs_etm_record_init(int *err) 526 + { 527 + struct perf_pmu *cs_etm_pmu; 528 + struct cs_etm_recording *ptr; 529 + 530 + cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME); 531 + 532 + if (!cs_etm_pmu) { 533 + *err = -EINVAL; 534 + goto out; 535 + } 536 + 537 + ptr = zalloc(sizeof(struct cs_etm_recording)); 538 + if (!ptr) { 539 + *err = -ENOMEM; 540 + goto out; 541 + } 542 + 543 + ptr->cs_etm_pmu = cs_etm_pmu; 544 + ptr->itr.parse_snapshot_options = cs_etm_parse_snapshot_options; 545 + ptr->itr.recording_options = cs_etm_recording_options; 546 + ptr->itr.info_priv_size = cs_etm_info_priv_size; 547 + ptr->itr.info_fill = cs_etm_info_fill; 548 + ptr->itr.find_snapshot = cs_etm_find_snapshot; 549 + ptr->itr.snapshot_start = cs_etm_snapshot_start; 550 + ptr->itr.snapshot_finish = cs_etm_snapshot_finish; 551 + ptr->itr.reference = cs_etm_reference; 552 + ptr->itr.free = cs_etm_recording_free; 553 + ptr->itr.read_finish = cs_etm_read_finish; 554 + 555 + *err = 0; 556 + return &ptr->itr; 557 + out: 558 + return NULL; 559 + }
+23
tools/perf/arch/arm/util/cs-etm.h
··· 1 + /* 2 + * Copyright(C) 2015 Linaro Limited. All rights reserved. 3 + * Author: Mathieu Poirier <mathieu.poirier@linaro.org> 4 + * 5 + * This program is free software; you can redistribute it and/or modify it 6 + * under the terms of the GNU General Public License version 2 as published by 7 + * the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, but WITHOUT 10 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 + * more details. 13 + * 14 + * You should have received a copy of the GNU General Public License along with 15 + * this program. If not, see <http://www.gnu.org/licenses/>. 16 + */ 17 + 18 + #ifndef INCLUDE__PERF_CS_ETM_H__ 19 + #define INCLUDE__PERF_CS_ETM_H__ 20 + 21 + struct auxtrace_record *cs_etm_record_init(int *err); 22 + 23 + #endif
+3 -1
tools/perf/arch/arm64/util/Build
··· 1 1 libperf-$(CONFIG_DWARF) += dwarf-regs.o 2 2 libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o 3 3 4 - libperf-$(CONFIG_AUXTRACE) += ../../arm/util/pmu.o 4 + libperf-$(CONFIG_AUXTRACE) += ../../arm/util/pmu.o \ 5 + ../../arm/util/auxtrace.o \ 6 + ../../arm/util/cs-etm.o
+1
tools/perf/util/auxtrace.c
··· 892 892 return intel_pt_process_auxtrace_info(event, session); 893 893 case PERF_AUXTRACE_INTEL_BTS: 894 894 return intel_bts_process_auxtrace_info(event, session); 895 + case PERF_AUXTRACE_CS_ETM: 895 896 case PERF_AUXTRACE_UNKNOWN: 896 897 default: 897 898 return -EINVAL;
+1
tools/perf/util/auxtrace.h
··· 41 41 PERF_AUXTRACE_UNKNOWN, 42 42 PERF_AUXTRACE_INTEL_PT, 43 43 PERF_AUXTRACE_INTEL_BTS, 44 + PERF_AUXTRACE_CS_ETM, 44 45 }; 45 46 46 47 enum itrace_period_type {
+74
tools/perf/util/cs-etm.h
··· 1 + /* 2 + * Copyright(C) 2015 Linaro Limited. All rights reserved. 3 + * Author: Mathieu Poirier <mathieu.poirier@linaro.org> 4 + * 5 + * This program is free software; you can redistribute it and/or modify it 6 + * under the terms of the GNU General Public License version 2 as published by 7 + * the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, but WITHOUT 10 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 + * more details. 13 + * 14 + * You should have received a copy of the GNU General Public License along with 15 + * this program. If not, see <http://www.gnu.org/licenses/>. 16 + */ 17 + 18 + #ifndef INCLUDE__UTIL_PERF_CS_ETM_H__ 19 + #define INCLUDE__UTIL_PERF_CS_ETM_H__ 20 + 21 + /* Versionning header in case things need tro change in the future. That way 22 + * decoding of old snapshot is still possible. 23 + */ 24 + enum { 25 + /* Starting with 0x0 */ 26 + CS_HEADER_VERSION_0, 27 + /* PMU->type (32 bit), total # of CPUs (32 bit) */ 28 + CS_PMU_TYPE_CPUS, 29 + CS_ETM_SNAPSHOT, 30 + CS_HEADER_VERSION_0_MAX, 31 + }; 32 + 33 + /* Beginning of header common to both ETMv3 and V4 */ 34 + enum { 35 + CS_ETM_MAGIC, 36 + CS_ETM_CPU, 37 + }; 38 + 39 + /* ETMv3/PTM metadata */ 40 + enum { 41 + /* Dynamic, configurable parameters */ 42 + CS_ETM_ETMCR = CS_ETM_CPU + 1, 43 + CS_ETM_ETMTRACEIDR, 44 + /* RO, taken from sysFS */ 45 + CS_ETM_ETMCCER, 46 + CS_ETM_ETMIDR, 47 + CS_ETM_PRIV_MAX, 48 + }; 49 + 50 + /* ETMv4 metadata */ 51 + enum { 52 + /* Dynamic, configurable parameters */ 53 + CS_ETMV4_TRCCONFIGR = CS_ETM_CPU + 1, 54 + CS_ETMV4_TRCTRACEIDR, 55 + /* RO, taken from sysFS */ 56 + CS_ETMV4_TRCIDR0, 57 + CS_ETMV4_TRCIDR1, 58 + CS_ETMV4_TRCIDR2, 59 + CS_ETMV4_TRCIDR8, 60 + CS_ETMV4_TRCAUTHSTATUS, 61 + CS_ETMV4_PRIV_MAX, 62 + }; 63 + 64 + #define KiB(x) ((x) * 1024) 65 + #define MiB(x) ((x) * 1024 * 1024) 66 + 67 + #define CS_ETM_HEADER_SIZE (CS_HEADER_VERSION_0_MAX * sizeof(u64)) 68 + 69 + static const u64 __perf_cs_etmv3_magic = 0x3030303030303030ULL; 70 + static const u64 __perf_cs_etmv4_magic = 0x4040404040404040ULL; 71 + #define CS_ETMV3_PRIV_SIZE (CS_ETM_PRIV_MAX * sizeof(u64)) 72 + #define CS_ETMV4_PRIV_SIZE (CS_ETMV4_PRIV_MAX * sizeof(u64)) 73 + 74 + #endif