1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Arm Statistical Profiling Extensions (SPE) support 4 * Copyright (c) 2017-2018, Arm Ltd. 5 */ 6 7 #include <linux/kernel.h> 8 #include <linux/types.h> 9 #include <linux/bitops.h> 10 #include <linux/log2.h> 11 #include <linux/string.h> 12 #include <linux/zalloc.h> 13 #include <time.h> 14 15 #include "../../../util/cpumap.h" 16 #include "../../../util/event.h" 17 #include "../../../util/evsel.h" 18 #include "../../../util/evsel_config.h" 19 #include "../../../util/evlist.h" 20 #include "../../../util/session.h" 21 #include <internal/lib.h> // page_size 22 #include "../../../util/pmu.h" 23 #include "../../../util/debug.h" 24 #include "../../../util/auxtrace.h" 25 #include "../../../util/record.h" 26 #include "../../../util/header.h" 27 #include "../../../util/arm-spe.h" 28 #include <tools/libc_compat.h> // reallocarray 29 30 #define ARM_SPE_CPU_MAGIC 0x1010101010101010ULL 31 32 #define KiB(x) ((x) * 1024) 33 #define MiB(x) ((x) * 1024 * 1024) 34 35 struct arm_spe_recording { 36 struct auxtrace_record itr; 37 struct perf_pmu *arm_spe_pmu; 38 struct evlist *evlist; 39 int wrapped_cnt; 40 bool *wrapped; 41 }; 42 43 /* Iterate config list to detect if the "freq" parameter is set */ 44 static bool arm_spe_is_set_freq(struct evsel *evsel) 45 { 46 struct evsel_config_term *term; 47 48 list_for_each_entry(term, &evsel->config_terms, list) { 49 if (term->type == EVSEL__CONFIG_TERM_FREQ) 50 return true; 51 } 52 53 return false; 54 } 55 56 /* 57 * arm_spe_find_cpus() returns a new cpu map, and the caller should invoke 58 * perf_cpu_map__put() to release the map after use. 59 */ 60 static struct perf_cpu_map *arm_spe_find_cpus(struct evlist *evlist) 61 { 62 struct perf_cpu_map *event_cpus = evlist->core.user_requested_cpus; 63 struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus(); 64 struct perf_cpu_map *intersect_cpus; 65 66 /* cpu map is not "any" CPU , we have specific CPUs to work with */ 67 if (!perf_cpu_map__has_any_cpu(event_cpus)) { 68 intersect_cpus = perf_cpu_map__intersect(event_cpus, online_cpus); 69 perf_cpu_map__put(online_cpus); 70 /* Event can be "any" CPU so count all CPUs. */ 71 } else { 72 intersect_cpus = online_cpus; 73 } 74 75 return intersect_cpus; 76 } 77 78 static size_t 79 arm_spe_info_priv_size(struct auxtrace_record *itr __maybe_unused, 80 struct evlist *evlist) 81 { 82 struct perf_cpu_map *cpu_map = arm_spe_find_cpus(evlist); 83 size_t size; 84 85 if (!cpu_map) 86 return 0; 87 88 size = ARM_SPE_AUXTRACE_PRIV_MAX + 89 ARM_SPE_CPU_PRIV_MAX * perf_cpu_map__nr(cpu_map); 90 size *= sizeof(u64); 91 92 perf_cpu_map__put(cpu_map); 93 return size; 94 } 95 96 static int arm_spe_save_cpu_header(struct auxtrace_record *itr, 97 struct perf_cpu cpu, __u64 data[]) 98 { 99 struct arm_spe_recording *sper = 100 container_of(itr, struct arm_spe_recording, itr); 101 struct perf_pmu *pmu = NULL; 102 char *cpuid = NULL; 103 u64 val; 104 105 /* Read CPU MIDR */ 106 cpuid = get_cpuid_allow_env_override(cpu); 107 if (!cpuid) 108 return -ENOMEM; 109 val = strtol(cpuid, NULL, 16); 110 111 data[ARM_SPE_MAGIC] = ARM_SPE_CPU_MAGIC; 112 data[ARM_SPE_CPU] = cpu.cpu; 113 data[ARM_SPE_CPU_NR_PARAMS] = ARM_SPE_CPU_PRIV_MAX - ARM_SPE_CPU_MIDR; 114 data[ARM_SPE_CPU_MIDR] = val; 115 116 /* Find the associate Arm SPE PMU for the CPU */ 117 if (perf_cpu_map__has(sper->arm_spe_pmu->cpus, cpu)) 118 pmu = sper->arm_spe_pmu; 119 120 if (!pmu) { 121 /* No Arm SPE PMU is found */ 122 data[ARM_SPE_CPU_PMU_TYPE] = ULLONG_MAX; 123 data[ARM_SPE_CAP_MIN_IVAL] = 0; 124 data[ARM_SPE_CAP_EVENT_FILTER] = 0; 125 } else { 126 data[ARM_SPE_CPU_PMU_TYPE] = pmu->type; 127 128 if (perf_pmu__scan_file(pmu, "caps/min_interval", "%lu", &val) != 1) 129 val = 0; 130 data[ARM_SPE_CAP_MIN_IVAL] = val; 131 132 if (perf_pmu__scan_file(pmu, "caps/event_filter", "%lx", &val) != 1) 133 val = 0; 134 data[ARM_SPE_CAP_EVENT_FILTER] = val; 135 } 136 137 free(cpuid); 138 return ARM_SPE_CPU_PRIV_MAX; 139 } 140 141 static int arm_spe_info_fill(struct auxtrace_record *itr, 142 struct perf_session *session, 143 struct perf_record_auxtrace_info *auxtrace_info, 144 size_t priv_size) 145 { 146 int i, ret; 147 size_t offset; 148 struct arm_spe_recording *sper = 149 container_of(itr, struct arm_spe_recording, itr); 150 struct perf_pmu *arm_spe_pmu = sper->arm_spe_pmu; 151 struct perf_cpu_map *cpu_map; 152 struct perf_cpu cpu; 153 __u64 *data; 154 155 if (priv_size != arm_spe_info_priv_size(itr, session->evlist)) 156 return -EINVAL; 157 158 if (!session->evlist->core.nr_mmaps) 159 return -EINVAL; 160 161 cpu_map = arm_spe_find_cpus(session->evlist); 162 if (!cpu_map) 163 return -EINVAL; 164 165 auxtrace_info->type = PERF_AUXTRACE_ARM_SPE; 166 auxtrace_info->priv[ARM_SPE_HEADER_VERSION] = ARM_SPE_HEADER_CURRENT_VERSION; 167 auxtrace_info->priv[ARM_SPE_HEADER_SIZE] = 168 ARM_SPE_AUXTRACE_PRIV_MAX - ARM_SPE_HEADER_VERSION; 169 auxtrace_info->priv[ARM_SPE_PMU_TYPE_V2] = arm_spe_pmu->type; 170 auxtrace_info->priv[ARM_SPE_CPUS_NUM] = perf_cpu_map__nr(cpu_map); 171 172 offset = ARM_SPE_AUXTRACE_PRIV_MAX; 173 perf_cpu_map__for_each_cpu(cpu, i, cpu_map) { 174 assert(offset < priv_size); 175 data = &auxtrace_info->priv[offset]; 176 ret = arm_spe_save_cpu_header(itr, cpu, data); 177 if (ret < 0) 178 goto out; 179 offset += ret; 180 } 181 182 ret = 0; 183 out: 184 perf_cpu_map__put(cpu_map); 185 return ret; 186 } 187 188 static void 189 arm_spe_snapshot_resolve_auxtrace_defaults(struct record_opts *opts, 190 bool privileged) 191 { 192 /* 193 * The default snapshot size is the auxtrace mmap size. If neither auxtrace mmap size nor 194 * snapshot size is specified, then the default is 4MiB for privileged users, 128KiB for 195 * unprivileged users. 196 * 197 * The default auxtrace mmap size is 4MiB/page_size for privileged users, 128KiB for 198 * unprivileged users. If an unprivileged user does not specify mmap pages, the mmap pages 199 * will be reduced from the default 512KiB/page_size to 256KiB/page_size, otherwise the 200 * user is likely to get an error as they exceed their mlock limmit. 201 */ 202 203 /* 204 * No size were given to '-S' or '-m,', so go with the default 205 */ 206 if (!opts->auxtrace_snapshot_size && !opts->auxtrace_mmap_pages) { 207 if (privileged) { 208 opts->auxtrace_mmap_pages = MiB(4) / page_size; 209 } else { 210 opts->auxtrace_mmap_pages = KiB(128) / page_size; 211 if (opts->mmap_pages == UINT_MAX) 212 opts->mmap_pages = KiB(256) / page_size; 213 } 214 } else if (!opts->auxtrace_mmap_pages && !privileged && opts->mmap_pages == UINT_MAX) { 215 opts->mmap_pages = KiB(256) / page_size; 216 } 217 218 /* 219 * '-m,xyz' was specified but no snapshot size, so make the snapshot size as big as the 220 * auxtrace mmap area. 221 */ 222 if (!opts->auxtrace_snapshot_size) 223 opts->auxtrace_snapshot_size = opts->auxtrace_mmap_pages * (size_t)page_size; 224 225 /* 226 * '-Sxyz' was specified but no auxtrace mmap area, so make the auxtrace mmap area big 227 * enough to fit the requested snapshot size. 228 */ 229 if (!opts->auxtrace_mmap_pages) { 230 size_t sz = opts->auxtrace_snapshot_size; 231 232 sz = round_up(sz, page_size) / page_size; 233 opts->auxtrace_mmap_pages = roundup_pow_of_two(sz); 234 } 235 } 236 237 static __u64 arm_spe_pmu__sample_period(const struct perf_pmu *arm_spe_pmu) 238 { 239 static __u64 sample_period; 240 241 if (sample_period) 242 return sample_period; 243 244 /* 245 * If kernel driver doesn't advertise a minimum, 246 * use max allowable by PMSIDR_EL1.INTERVAL 247 */ 248 if (perf_pmu__scan_file(arm_spe_pmu, "caps/min_interval", "%llu", 249 &sample_period) != 1) { 250 pr_debug("arm_spe driver doesn't advertise a min. interval. Using 4096\n"); 251 sample_period = 4096; 252 } 253 return sample_period; 254 } 255 256 static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus) 257 { 258 u64 bit; 259 260 evsel->core.attr.freq = 0; 261 evsel->core.attr.sample_period = arm_spe_pmu__sample_period(evsel->pmu); 262 evsel->needs_auxtrace_mmap = true; 263 264 /* 265 * To obtain the auxtrace buffer file descriptor, the auxtrace event 266 * must come first. 267 */ 268 evlist__to_front(evsel->evlist, evsel); 269 270 /* 271 * In the case of per-cpu mmaps, sample CPU for AUX event; 272 * also enable the timestamp tracing for samples correlation. 273 */ 274 if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus)) { 275 evsel__set_sample_bit(evsel, CPU); 276 evsel__set_config_if_unset(evsel->pmu, evsel, "ts_enable", 1); 277 } 278 279 /* 280 * Set this only so that perf report knows that SPE generates memory info. It has no effect 281 * on the opening of the event or the SPE data produced. 282 */ 283 evsel__set_sample_bit(evsel, DATA_SRC); 284 285 /* 286 * The PHYS_ADDR flag does not affect the driver behaviour, it is used to 287 * inform that the resulting output's SPE samples contain physical addresses 288 * where applicable. 289 */ 290 bit = perf_pmu__format_bits(evsel->pmu, "pa_enable"); 291 if (evsel->core.attr.config & bit) 292 evsel__set_sample_bit(evsel, PHYS_ADDR); 293 } 294 295 static int arm_spe_setup_aux_buffer(struct record_opts *opts) 296 { 297 bool privileged = perf_event_paranoid_check(-1); 298 299 /* 300 * we are in snapshot mode. 301 */ 302 if (opts->auxtrace_snapshot_mode) { 303 /* 304 * Command arguments '-Sxyz' and/or '-m,xyz' are missing, so fill those in with 305 * default values. 306 */ 307 if (!opts->auxtrace_snapshot_size || !opts->auxtrace_mmap_pages) 308 arm_spe_snapshot_resolve_auxtrace_defaults(opts, privileged); 309 310 /* 311 * Snapshot size can't be bigger than the auxtrace area. 312 */ 313 if (opts->auxtrace_snapshot_size > opts->auxtrace_mmap_pages * (size_t)page_size) { 314 pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n", 315 opts->auxtrace_snapshot_size, 316 opts->auxtrace_mmap_pages * (size_t)page_size); 317 return -EINVAL; 318 } 319 320 /* 321 * Something went wrong somewhere - this shouldn't happen. 322 */ 323 if (!opts->auxtrace_snapshot_size || !opts->auxtrace_mmap_pages) { 324 pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n"); 325 return -EINVAL; 326 } 327 328 pr_debug2("%sx snapshot size: %zu\n", ARM_SPE_PMU_NAME, 329 opts->auxtrace_snapshot_size); 330 } 331 332 /* We are in full trace mode but '-m,xyz' wasn't specified */ 333 if (!opts->auxtrace_mmap_pages) { 334 if (privileged) { 335 opts->auxtrace_mmap_pages = MiB(4) / page_size; 336 } else { 337 opts->auxtrace_mmap_pages = KiB(128) / page_size; 338 if (opts->mmap_pages == UINT_MAX) 339 opts->mmap_pages = KiB(256) / page_size; 340 } 341 } 342 343 /* Validate auxtrace_mmap_pages */ 344 if (opts->auxtrace_mmap_pages) { 345 size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size; 346 size_t min_sz = KiB(8); 347 348 if (sz < min_sz || !is_power_of_2(sz)) { 349 pr_err("Invalid mmap size for ARM SPE: must be at least %zuKiB and a power of 2\n", 350 min_sz / 1024); 351 return -EINVAL; 352 } 353 } 354 355 return 0; 356 } 357 358 static int arm_spe_setup_tracking_event(struct evlist *evlist, 359 struct record_opts *opts) 360 { 361 int err; 362 struct evsel *tracking_evsel; 363 struct perf_cpu_map *cpus = evlist->core.user_requested_cpus; 364 365 /* Add dummy event to keep tracking */ 366 err = parse_event(evlist, "dummy:u"); 367 if (err) 368 return err; 369 370 tracking_evsel = evlist__last(evlist); 371 evlist__set_tracking_event(evlist, tracking_evsel); 372 373 tracking_evsel->core.attr.freq = 0; 374 tracking_evsel->core.attr.sample_period = 1; 375 376 /* In per-cpu case, always need the time of mmap events etc */ 377 if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus)) { 378 evsel__set_sample_bit(tracking_evsel, TIME); 379 evsel__set_sample_bit(tracking_evsel, CPU); 380 381 /* also track task context switch */ 382 if (!record_opts__no_switch_events(opts)) 383 tracking_evsel->core.attr.context_switch = 1; 384 } 385 386 return 0; 387 } 388 389 static int arm_spe_recording_options(struct auxtrace_record *itr, 390 struct evlist *evlist, 391 struct record_opts *opts) 392 { 393 struct arm_spe_recording *sper = 394 container_of(itr, struct arm_spe_recording, itr); 395 struct evsel *evsel, *tmp; 396 struct perf_cpu_map *cpus = evlist->core.user_requested_cpus; 397 bool discard = false; 398 int err; 399 400 sper->evlist = evlist; 401 402 evlist__for_each_entry(evlist, evsel) { 403 if (evsel__is_aux_event(evsel)) { 404 if (!strstarts(evsel->pmu->name, ARM_SPE_PMU_NAME)) { 405 pr_err("Found unexpected auxtrace event: %s\n", 406 evsel->pmu->name); 407 return -EINVAL; 408 } 409 opts->full_auxtrace = true; 410 411 if (opts->user_freq != UINT_MAX || 412 arm_spe_is_set_freq(evsel)) { 413 pr_err("Arm SPE: Frequency is not supported. " 414 "Set period with -c option or PMU parameter (-e %s/period=NUM/).\n", 415 evsel->pmu->name); 416 return -EINVAL; 417 } 418 } 419 } 420 421 if (!opts->full_auxtrace) 422 return 0; 423 424 evlist__for_each_entry_safe(evlist, tmp, evsel) { 425 if (evsel__is_aux_event(evsel)) { 426 arm_spe_setup_evsel(evsel, cpus); 427 if (evsel->core.attr.config & 428 perf_pmu__format_bits(evsel->pmu, "discard")) 429 discard = true; 430 } 431 } 432 433 if (discard) 434 return 0; 435 436 err = arm_spe_setup_aux_buffer(opts); 437 if (err) 438 return err; 439 440 return arm_spe_setup_tracking_event(evlist, opts); 441 } 442 443 static int arm_spe_parse_snapshot_options(struct auxtrace_record *itr __maybe_unused, 444 struct record_opts *opts, 445 const char *str) 446 { 447 unsigned long long snapshot_size = 0; 448 char *endptr; 449 450 if (str) { 451 snapshot_size = strtoull(str, &endptr, 0); 452 if (*endptr || snapshot_size > SIZE_MAX) 453 return -1; 454 } 455 456 opts->auxtrace_snapshot_mode = true; 457 opts->auxtrace_snapshot_size = snapshot_size; 458 459 return 0; 460 } 461 462 static int arm_spe_snapshot_start(struct auxtrace_record *itr) 463 { 464 struct arm_spe_recording *ptr = 465 container_of(itr, struct arm_spe_recording, itr); 466 struct evsel *evsel; 467 int ret = -EINVAL; 468 469 evlist__for_each_entry(ptr->evlist, evsel) { 470 if (evsel__is_aux_event(evsel)) { 471 ret = evsel__disable(evsel); 472 if (ret < 0) 473 return ret; 474 } 475 } 476 return ret; 477 } 478 479 static int arm_spe_snapshot_finish(struct auxtrace_record *itr) 480 { 481 struct arm_spe_recording *ptr = 482 container_of(itr, struct arm_spe_recording, itr); 483 struct evsel *evsel; 484 int ret = -EINVAL; 485 486 evlist__for_each_entry(ptr->evlist, evsel) { 487 if (evsel__is_aux_event(evsel)) { 488 ret = evsel__enable(evsel); 489 if (ret < 0) 490 return ret; 491 } 492 } 493 return ret; 494 } 495 496 static int arm_spe_alloc_wrapped_array(struct arm_spe_recording *ptr, int idx) 497 { 498 bool *wrapped; 499 int cnt = ptr->wrapped_cnt, new_cnt, i; 500 501 /* 502 * No need to allocate, so return early. 503 */ 504 if (idx < cnt) 505 return 0; 506 507 /* 508 * Make ptr->wrapped as big as idx. 509 */ 510 new_cnt = idx + 1; 511 512 /* 513 * Free'ed in arm_spe_recording_free(). 514 */ 515 wrapped = reallocarray(ptr->wrapped, new_cnt, sizeof(bool)); 516 if (!wrapped) 517 return -ENOMEM; 518 519 /* 520 * init new allocated values. 521 */ 522 for (i = cnt; i < new_cnt; i++) 523 wrapped[i] = false; 524 525 ptr->wrapped_cnt = new_cnt; 526 ptr->wrapped = wrapped; 527 528 return 0; 529 } 530 531 static bool arm_spe_buffer_has_wrapped(unsigned char *buffer, 532 size_t buffer_size, u64 head) 533 { 534 u64 i, watermark; 535 u64 *buf = (u64 *)buffer; 536 size_t buf_size = buffer_size; 537 538 /* 539 * Defensively handle the case where head might be continually increasing - if its value is 540 * equal or greater than the size of the ring buffer, then we can safely determine it has 541 * wrapped around. Otherwise, continue to detect if head might have wrapped. 542 */ 543 if (head >= buffer_size) 544 return true; 545 546 /* 547 * We want to look the very last 512 byte (chosen arbitrarily) in the ring buffer. 548 */ 549 watermark = buf_size - 512; 550 551 /* 552 * The value of head is somewhere within the size of the ring buffer. This can be that there 553 * hasn't been enough data to fill the ring buffer yet or the trace time was so long that 554 * head has numerically wrapped around. To find we need to check if we have data at the 555 * very end of the ring buffer. We can reliably do this because mmap'ed pages are zeroed 556 * out and there is a fresh mapping with every new session. 557 */ 558 559 /* 560 * head is less than 512 byte from the end of the ring buffer. 561 */ 562 if (head > watermark) 563 watermark = head; 564 565 /* 566 * Speed things up by using 64 bit transactions (see "u64 *buf" above) 567 */ 568 watermark /= sizeof(u64); 569 buf_size /= sizeof(u64); 570 571 /* 572 * If we find trace data at the end of the ring buffer, head has been there and has 573 * numerically wrapped around at least once. 574 */ 575 for (i = watermark; i < buf_size; i++) 576 if (buf[i]) 577 return true; 578 579 return false; 580 } 581 582 static int arm_spe_find_snapshot(struct auxtrace_record *itr, int idx, 583 struct auxtrace_mmap *mm, unsigned char *data, 584 u64 *head, u64 *old) 585 { 586 int err; 587 bool wrapped; 588 struct arm_spe_recording *ptr = 589 container_of(itr, struct arm_spe_recording, itr); 590 591 /* 592 * Allocate memory to keep track of wrapping if this is the first 593 * time we deal with this *mm. 594 */ 595 if (idx >= ptr->wrapped_cnt) { 596 err = arm_spe_alloc_wrapped_array(ptr, idx); 597 if (err) 598 return err; 599 } 600 601 /* 602 * Check to see if *head has wrapped around. If it hasn't only the 603 * amount of data between *head and *old is snapshot'ed to avoid 604 * bloating the perf.data file with zeros. But as soon as *head has 605 * wrapped around the entire size of the AUX ring buffer it taken. 606 */ 607 wrapped = ptr->wrapped[idx]; 608 if (!wrapped && arm_spe_buffer_has_wrapped(data, mm->len, *head)) { 609 wrapped = true; 610 ptr->wrapped[idx] = true; 611 } 612 613 pr_debug3("%s: mmap index %d old head %zu new head %zu size %zu\n", 614 __func__, idx, (size_t)*old, (size_t)*head, mm->len); 615 616 /* 617 * No wrap has occurred, we can just use *head and *old. 618 */ 619 if (!wrapped) 620 return 0; 621 622 /* 623 * *head has wrapped around - adjust *head and *old to pickup the 624 * entire content of the AUX buffer. 625 */ 626 if (*head >= mm->len) { 627 *old = *head - mm->len; 628 } else { 629 *head += mm->len; 630 *old = *head - mm->len; 631 } 632 633 return 0; 634 } 635 636 static u64 arm_spe_reference(struct auxtrace_record *itr __maybe_unused) 637 { 638 struct timespec ts; 639 640 clock_gettime(CLOCK_MONOTONIC_RAW, &ts); 641 642 return ts.tv_sec ^ ts.tv_nsec; 643 } 644 645 static void arm_spe_recording_free(struct auxtrace_record *itr) 646 { 647 struct arm_spe_recording *sper = 648 container_of(itr, struct arm_spe_recording, itr); 649 650 zfree(&sper->wrapped); 651 free(sper); 652 } 653 654 struct auxtrace_record *arm_spe_recording_init(int *err, 655 struct perf_pmu *arm_spe_pmu) 656 { 657 struct arm_spe_recording *sper; 658 659 if (!arm_spe_pmu) { 660 *err = -ENODEV; 661 return NULL; 662 } 663 664 sper = zalloc(sizeof(struct arm_spe_recording)); 665 if (!sper) { 666 *err = -ENOMEM; 667 return NULL; 668 } 669 670 sper->arm_spe_pmu = arm_spe_pmu; 671 sper->itr.snapshot_start = arm_spe_snapshot_start; 672 sper->itr.snapshot_finish = arm_spe_snapshot_finish; 673 sper->itr.find_snapshot = arm_spe_find_snapshot; 674 sper->itr.parse_snapshot_options = arm_spe_parse_snapshot_options; 675 sper->itr.recording_options = arm_spe_recording_options; 676 sper->itr.info_priv_size = arm_spe_info_priv_size; 677 sper->itr.info_fill = arm_spe_info_fill; 678 sper->itr.free = arm_spe_recording_free; 679 sper->itr.reference = arm_spe_reference; 680 sper->itr.read_finish = auxtrace_record__read_finish; 681 sper->itr.alignment = 0; 682 683 *err = 0; 684 return &sper->itr; 685 } 686 687 void 688 arm_spe_pmu_default_config(const struct perf_pmu *arm_spe_pmu, struct perf_event_attr *attr) 689 { 690 attr->sample_period = arm_spe_pmu__sample_period(arm_spe_pmu); 691 } 692