1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * VPA DTL PMU support 4 */ 5 6 #include <linux/string.h> 7 #include <linux/zalloc.h> 8 #include <errno.h> 9 #include <inttypes.h> 10 #include "color.h" 11 #include "evlist.h" 12 #include "session.h" 13 #include "auxtrace.h" 14 #include "data.h" 15 #include "machine.h" 16 #include "debug.h" 17 #include "powerpc-vpadtl.h" 18 #include "sample.h" 19 #include "tool.h" 20 21 /* 22 * Structure to save the auxtrace queue 23 */ 24 struct powerpc_vpadtl { 25 struct auxtrace auxtrace; 26 struct auxtrace_queues queues; 27 struct auxtrace_heap heap; 28 u32 auxtrace_type; 29 struct perf_session *session; 30 struct machine *machine; 31 u32 pmu_type; 32 u64 sample_id; 33 }; 34 35 struct boottb_freq { 36 u64 boot_tb; 37 u64 tb_freq; 38 u64 timebase; 39 u64 padded[3]; 40 }; 41 42 struct powerpc_vpadtl_queue { 43 struct powerpc_vpadtl *vpa; 44 unsigned int queue_nr; 45 struct auxtrace_buffer *buffer; 46 struct thread *thread; 47 bool on_heap; 48 struct powerpc_vpadtl_entry *dtl; 49 u64 timestamp; 50 unsigned long pkt_len; 51 unsigned long buf_len; 52 u64 boot_tb; 53 u64 tb_freq; 54 unsigned int tb_buffer; 55 unsigned int size; 56 bool done; 57 pid_t pid; 58 pid_t tid; 59 int cpu; 60 }; 61 62 const char *dispatch_reasons[11] = { 63 "external_interrupt", 64 "firmware_internal_event", 65 "H_PROD", 66 "decrementer_interrupt", 67 "system_reset", 68 "firmware_internal_event", 69 "conferred_cycles", 70 "time_slice", 71 "virtual_memory_page_fault", 72 "expropriated_adjunct", 73 "priv_doorbell"}; 74 75 const char *preempt_reasons[10] = { 76 "unused", 77 "firmware_internal_event", 78 "H_CEDE", 79 "H_CONFER", 80 "time_slice", 81 "migration_hibernation_page_fault", 82 "virtual_memory_page_fault", 83 "H_CONFER_ADJUNCT", 84 "hcall_adjunct", 85 "HDEC_adjunct"}; 86 87 #define dtl_entry_size sizeof(struct powerpc_vpadtl_entry) 88 89 /* 90 * Function to dump the dispatch trace data when perf report 91 * is invoked with -D 92 */ 93 static void powerpc_vpadtl_dump(struct powerpc_vpadtl *vpa __maybe_unused, 94 unsigned char *buf, size_t len) 95 { 96 struct powerpc_vpadtl_entry *dtl; 97 int pkt_len, pos = 0; 98 const char *color = PERF_COLOR_BLUE; 99 100 color_fprintf(stdout, color, 101 ". ... VPA DTL PMU data: size %zu bytes, entries is %zu\n", 102 len, len/dtl_entry_size); 103 104 if (len % dtl_entry_size) 105 len = len - (len % dtl_entry_size); 106 107 while (len) { 108 pkt_len = dtl_entry_size; 109 printf("."); 110 color_fprintf(stdout, color, " %08x: ", pos); 111 dtl = (struct powerpc_vpadtl_entry *)buf; 112 if (dtl->timebase != 0) { 113 printf("dispatch_reason:%s, preempt_reason:%s, " 114 "enqueue_to_dispatch_time:%d, ready_to_enqueue_time:%d, " 115 "waiting_to_ready_time:%d\n", 116 dispatch_reasons[dtl->dispatch_reason], 117 preempt_reasons[dtl->preempt_reason], 118 be32_to_cpu(dtl->enqueue_to_dispatch_time), 119 be32_to_cpu(dtl->ready_to_enqueue_time), 120 be32_to_cpu(dtl->waiting_to_ready_time)); 121 } else { 122 struct boottb_freq *boot_tb = (struct boottb_freq *)buf; 123 124 printf("boot_tb: %" PRIu64 ", tb_freq: %" PRIu64 "\n", 125 boot_tb->boot_tb, boot_tb->tb_freq); 126 } 127 128 pos += pkt_len; 129 buf += pkt_len; 130 len -= pkt_len; 131 } 132 } 133 134 static unsigned long long powerpc_vpadtl_timestamp(struct powerpc_vpadtl_queue *vpaq) 135 { 136 struct powerpc_vpadtl_entry *record = vpaq->dtl; 137 unsigned long long timestamp = 0; 138 unsigned long long boot_tb; 139 unsigned long long diff; 140 double result, div; 141 double boot_freq; 142 /* 143 * Formula used to get timestamp that can be co-related with 144 * other perf events: 145 * ((timbase from DTL entry - boot time) / frequency) * 1000000000 146 */ 147 if (record->timebase) { 148 boot_tb = vpaq->boot_tb; 149 boot_freq = vpaq->tb_freq; 150 diff = be64_to_cpu(record->timebase) - boot_tb; 151 div = diff / boot_freq; 152 result = div; 153 result = result * 1000000000; 154 timestamp = result; 155 } 156 157 return timestamp; 158 } 159 160 static struct powerpc_vpadtl *session_to_vpa(struct perf_session *session) 161 { 162 return container_of(session->auxtrace, struct powerpc_vpadtl, auxtrace); 163 } 164 165 static void powerpc_vpadtl_dump_event(struct powerpc_vpadtl *vpa, unsigned char *buf, 166 size_t len) 167 { 168 printf(".\n"); 169 powerpc_vpadtl_dump(vpa, buf, len); 170 } 171 172 /* 173 * Generate perf sample for each entry in the dispatch trace log. 174 * - sample ip is picked from srr0 field of powerpc_vpadtl_entry 175 * - sample cpu is logical cpu. 176 * - cpumode is set to PERF_RECORD_MISC_KERNEL 177 * - Additionally save the details in raw_data of sample. This 178 * is to print the relevant fields in perf_sample__fprintf_synth() 179 * when called from builtin-script 180 */ 181 static int powerpc_vpadtl_sample(struct powerpc_vpadtl_entry *record, 182 struct powerpc_vpadtl *vpa, u64 save, int cpu) 183 { 184 struct perf_sample sample; 185 union perf_event event; 186 int ret; 187 188 perf_sample__init(&sample, /*all=*/true); 189 sample.ip = be64_to_cpu(record->srr0); 190 sample.period = 1; 191 sample.cpu = cpu; 192 sample.id = vpa->sample_id; 193 sample.callchain = NULL; 194 sample.branch_stack = NULL; 195 memset(&event, 0, sizeof(event)); 196 sample.cpumode = PERF_RECORD_MISC_KERNEL; 197 sample.time = save; 198 sample.raw_data = record; 199 sample.raw_size = sizeof(record); 200 event.sample.header.type = PERF_RECORD_SAMPLE; 201 event.sample.header.misc = sample.cpumode; 202 event.sample.header.size = sizeof(struct perf_event_header); 203 204 ret = perf_session__deliver_synth_event(vpa->session, &event, &sample); 205 if (ret) 206 pr_debug("Failed to create sample for dtl entry\n"); 207 208 perf_sample__exit(&sample); 209 return ret; 210 } 211 212 static int powerpc_vpadtl_get_buffer(struct powerpc_vpadtl_queue *vpaq) 213 { 214 struct auxtrace_buffer *buffer = vpaq->buffer; 215 struct auxtrace_queues *queues = &vpaq->vpa->queues; 216 struct auxtrace_queue *queue; 217 218 queue = &queues->queue_array[vpaq->queue_nr]; 219 buffer = auxtrace_buffer__next(queue, buffer); 220 221 if (!buffer) 222 return 0; 223 224 vpaq->buffer = buffer; 225 vpaq->size = buffer->size; 226 227 /* If the aux_buffer doesn't have data associated, try to load it */ 228 if (!buffer->data) { 229 /* get the file desc associated with the perf data file */ 230 int fd = perf_data__fd(vpaq->vpa->session->data); 231 232 buffer->data = auxtrace_buffer__get_data(buffer, fd); 233 if (!buffer->data) 234 return -ENOMEM; 235 } 236 237 vpaq->buf_len = buffer->size; 238 239 if (buffer->size % dtl_entry_size) 240 vpaq->buf_len = buffer->size - (buffer->size % dtl_entry_size); 241 242 if (vpaq->tb_buffer != buffer->buffer_nr) { 243 vpaq->pkt_len = 0; 244 vpaq->tb_buffer = 0; 245 } 246 247 return 1; 248 } 249 250 /* 251 * The first entry in the queue for VPA DTL PMU has the boot timebase, 252 * frequency details which are needed to get timestamp which is required to 253 * correlate with other events. Save the boot_tb and tb_freq as part of 254 * powerpc_vpadtl_queue. The very next entry is the actual trace data to 255 * be returned. 256 */ 257 static int powerpc_vpadtl_decode(struct powerpc_vpadtl_queue *vpaq) 258 { 259 int ret; 260 char *buf; 261 struct boottb_freq *boottb; 262 263 ret = powerpc_vpadtl_get_buffer(vpaq); 264 if (ret <= 0) 265 return ret; 266 267 boottb = (struct boottb_freq *)vpaq->buffer->data; 268 if (boottb->timebase == 0) { 269 vpaq->boot_tb = boottb->boot_tb; 270 vpaq->tb_freq = boottb->tb_freq; 271 vpaq->pkt_len += dtl_entry_size; 272 } 273 274 buf = vpaq->buffer->data; 275 buf += vpaq->pkt_len; 276 vpaq->dtl = (struct powerpc_vpadtl_entry *)buf; 277 278 vpaq->tb_buffer = vpaq->buffer->buffer_nr; 279 vpaq->buffer = NULL; 280 vpaq->buf_len = 0; 281 282 return 1; 283 } 284 285 static int powerpc_vpadtl_decode_all(struct powerpc_vpadtl_queue *vpaq) 286 { 287 int ret; 288 unsigned char *buf; 289 290 if (!vpaq->buf_len || vpaq->pkt_len == vpaq->size) { 291 ret = powerpc_vpadtl_get_buffer(vpaq); 292 if (ret <= 0) 293 return ret; 294 } 295 296 if (vpaq->buffer) { 297 buf = vpaq->buffer->data; 298 buf += vpaq->pkt_len; 299 vpaq->dtl = (struct powerpc_vpadtl_entry *)buf; 300 if ((long long)be64_to_cpu(vpaq->dtl->timebase) <= 0) { 301 if (vpaq->pkt_len != dtl_entry_size && vpaq->buf_len) { 302 vpaq->pkt_len += dtl_entry_size; 303 vpaq->buf_len -= dtl_entry_size; 304 } 305 return -1; 306 } 307 vpaq->pkt_len += dtl_entry_size; 308 vpaq->buf_len -= dtl_entry_size; 309 } else { 310 return 0; 311 } 312 313 return 1; 314 } 315 316 static int powerpc_vpadtl_run_decoder(struct powerpc_vpadtl_queue *vpaq, u64 *timestamp) 317 { 318 struct powerpc_vpadtl *vpa = vpaq->vpa; 319 struct powerpc_vpadtl_entry *record; 320 int ret; 321 unsigned long long vpaq_timestamp; 322 323 while (1) { 324 ret = powerpc_vpadtl_decode_all(vpaq); 325 if (!ret) { 326 pr_debug("All data in the queue has been processed.\n"); 327 return 1; 328 } 329 330 /* 331 * Error is detected when decoding VPA PMU trace. Continue to 332 * the next trace data and find out more dtl entries. 333 */ 334 if (ret < 0) 335 continue; 336 337 record = vpaq->dtl; 338 339 vpaq_timestamp = powerpc_vpadtl_timestamp(vpaq); 340 341 /* Update timestamp for the last record */ 342 if (vpaq_timestamp > vpaq->timestamp) 343 vpaq->timestamp = vpaq_timestamp; 344 345 /* 346 * If the timestamp of the queue is later than timestamp of the 347 * coming perf event, bail out so can allow the perf event to 348 * be processed ahead. 349 */ 350 if (vpaq->timestamp >= *timestamp) { 351 *timestamp = vpaq->timestamp; 352 vpaq->pkt_len -= dtl_entry_size; 353 vpaq->buf_len += dtl_entry_size; 354 return 0; 355 } 356 357 ret = powerpc_vpadtl_sample(record, vpa, vpaq_timestamp, vpaq->cpu); 358 if (ret) 359 continue; 360 } 361 return 0; 362 } 363 364 /* 365 * For each of the PERF_RECORD_XX record, compare the timestamp 366 * of perf record with timestamp of top element in the auxtrace heap. 367 * Process the auxtrace queue if the timestamp of element from heap is 368 * lower than timestamp from entry in perf record. 369 * 370 * Update the timestamp of the auxtrace heap with the timestamp 371 * of last processed entry from the auxtrace buffer. 372 */ 373 static int powerpc_vpadtl_process_queues(struct powerpc_vpadtl *vpa, u64 timestamp) 374 { 375 unsigned int queue_nr; 376 u64 ts; 377 int ret; 378 379 while (1) { 380 struct auxtrace_queue *queue; 381 struct powerpc_vpadtl_queue *vpaq; 382 383 if (!vpa->heap.heap_cnt) 384 return 0; 385 386 if (vpa->heap.heap_array[0].ordinal >= timestamp) 387 return 0; 388 389 queue_nr = vpa->heap.heap_array[0].queue_nr; 390 queue = &vpa->queues.queue_array[queue_nr]; 391 vpaq = queue->priv; 392 393 auxtrace_heap__pop(&vpa->heap); 394 395 if (vpa->heap.heap_cnt) { 396 ts = vpa->heap.heap_array[0].ordinal + 1; 397 if (ts > timestamp) 398 ts = timestamp; 399 } else { 400 ts = timestamp; 401 } 402 403 ret = powerpc_vpadtl_run_decoder(vpaq, &ts); 404 if (ret < 0) { 405 auxtrace_heap__add(&vpa->heap, queue_nr, ts); 406 return ret; 407 } 408 409 if (!ret) { 410 ret = auxtrace_heap__add(&vpa->heap, queue_nr, ts); 411 if (ret < 0) 412 return ret; 413 } else { 414 vpaq->on_heap = false; 415 } 416 } 417 return 0; 418 } 419 420 static struct powerpc_vpadtl_queue *powerpc_vpadtl__alloc_queue(struct powerpc_vpadtl *vpa, 421 unsigned int queue_nr) 422 { 423 struct powerpc_vpadtl_queue *vpaq; 424 425 vpaq = zalloc(sizeof(*vpaq)); 426 if (!vpaq) 427 return NULL; 428 429 vpaq->vpa = vpa; 430 vpaq->queue_nr = queue_nr; 431 432 return vpaq; 433 } 434 435 /* 436 * When the Dispatch Trace Log data is collected along with other events 437 * like sched tracepoint events, it needs to be correlated and present 438 * interleaved along with these events. Perf events can be collected 439 * parallely across the CPUs. 440 * 441 * An auxtrace_queue is created for each CPU. Data within each queue is in 442 * increasing order of timestamp. Allocate and setup auxtrace queues here. 443 * All auxtrace queues is maintained in auxtrace heap in the increasing order 444 * of timestamp. So always the lowest timestamp (entries to be processed first) 445 * is on top of the heap. 446 * 447 * To add to auxtrace heap, fetch the timestamp from first DTL entry 448 * for each of the queue. 449 */ 450 static int powerpc_vpadtl__setup_queue(struct powerpc_vpadtl *vpa, 451 struct auxtrace_queue *queue, 452 unsigned int queue_nr) 453 { 454 struct powerpc_vpadtl_queue *vpaq = queue->priv; 455 456 if (list_empty(&queue->head) || vpaq) 457 return 0; 458 459 vpaq = powerpc_vpadtl__alloc_queue(vpa, queue_nr); 460 if (!vpaq) 461 return -ENOMEM; 462 463 queue->priv = vpaq; 464 465 if (queue->cpu != -1) 466 vpaq->cpu = queue->cpu; 467 468 if (!vpaq->on_heap) { 469 int ret; 470 retry: 471 ret = powerpc_vpadtl_decode(vpaq); 472 if (!ret) 473 return 0; 474 475 if (ret < 0) 476 goto retry; 477 478 vpaq->timestamp = powerpc_vpadtl_timestamp(vpaq); 479 480 ret = auxtrace_heap__add(&vpa->heap, queue_nr, vpaq->timestamp); 481 if (ret) 482 return ret; 483 vpaq->on_heap = true; 484 } 485 486 return 0; 487 } 488 489 static int powerpc_vpadtl__setup_queues(struct powerpc_vpadtl *vpa) 490 { 491 unsigned int i; 492 int ret; 493 494 for (i = 0; i < vpa->queues.nr_queues; i++) { 495 ret = powerpc_vpadtl__setup_queue(vpa, &vpa->queues.queue_array[i], i); 496 if (ret) 497 return ret; 498 } 499 500 return 0; 501 } 502 503 static int powerpc_vpadtl__update_queues(struct powerpc_vpadtl *vpa) 504 { 505 if (vpa->queues.new_data) { 506 vpa->queues.new_data = false; 507 return powerpc_vpadtl__setup_queues(vpa); 508 } 509 510 return 0; 511 } 512 513 static int powerpc_vpadtl_process_event(struct perf_session *session, 514 union perf_event *event __maybe_unused, 515 struct perf_sample *sample, 516 const struct perf_tool *tool) 517 { 518 struct powerpc_vpadtl *vpa = session_to_vpa(session); 519 int err = 0; 520 521 if (dump_trace) 522 return 0; 523 524 if (!tool->ordered_events) { 525 pr_err("VPA requires ordered events\n"); 526 return -EINVAL; 527 } 528 529 if (sample->time) { 530 err = powerpc_vpadtl__update_queues(vpa); 531 if (err) 532 return err; 533 534 err = powerpc_vpadtl_process_queues(vpa, sample->time); 535 } 536 537 return err; 538 } 539 540 /* 541 * Process PERF_RECORD_AUXTRACE records 542 */ 543 static int powerpc_vpadtl_process_auxtrace_event(struct perf_session *session, 544 union perf_event *event, 545 const struct perf_tool *tool __maybe_unused) 546 { 547 struct powerpc_vpadtl *vpa = session_to_vpa(session); 548 struct auxtrace_buffer *buffer; 549 int fd = perf_data__fd(session->data); 550 off_t data_offset; 551 int err; 552 553 if (!dump_trace) 554 return 0; 555 556 if (perf_data__is_pipe(session->data)) { 557 data_offset = 0; 558 } else { 559 data_offset = lseek(fd, 0, SEEK_CUR); 560 if (data_offset == -1) 561 return -errno; 562 } 563 564 err = auxtrace_queues__add_event(&vpa->queues, session, event, 565 data_offset, &buffer); 566 567 if (err) 568 return err; 569 570 /* Dump here now we have copied a piped trace out of the pipe */ 571 if (auxtrace_buffer__get_data(buffer, fd)) { 572 powerpc_vpadtl_dump_event(vpa, buffer->data, buffer->size); 573 auxtrace_buffer__put_data(buffer); 574 } 575 576 return 0; 577 } 578 579 static int powerpc_vpadtl_flush(struct perf_session *session __maybe_unused, 580 const struct perf_tool *tool __maybe_unused) 581 { 582 return 0; 583 } 584 585 static void powerpc_vpadtl_free_events(struct perf_session *session) 586 { 587 struct powerpc_vpadtl *vpa = session_to_vpa(session); 588 struct auxtrace_queues *queues = &vpa->queues; 589 590 for (unsigned int i = 0; i < queues->nr_queues; i++) 591 zfree(&queues->queue_array[i].priv); 592 593 auxtrace_queues__free(queues); 594 } 595 596 static void powerpc_vpadtl_free(struct perf_session *session) 597 { 598 struct powerpc_vpadtl *vpa = session_to_vpa(session); 599 600 auxtrace_heap__free(&vpa->heap); 601 powerpc_vpadtl_free_events(session); 602 session->auxtrace = NULL; 603 free(vpa); 604 } 605 606 static const char * const powerpc_vpadtl_info_fmts[] = { 607 [POWERPC_VPADTL_TYPE] = " PMU Type %"PRId64"\n", 608 }; 609 610 static void powerpc_vpadtl_print_info(__u64 *arr) 611 { 612 if (!dump_trace) 613 return; 614 615 fprintf(stdout, powerpc_vpadtl_info_fmts[POWERPC_VPADTL_TYPE], arr[POWERPC_VPADTL_TYPE]); 616 } 617 618 static void set_event_name(struct evlist *evlist, u64 id, 619 const char *name) 620 { 621 struct evsel *evsel; 622 623 evlist__for_each_entry(evlist, evsel) { 624 if (evsel->core.id && evsel->core.id[0] == id) { 625 if (evsel->name) 626 zfree(&evsel->name); 627 evsel->name = strdup(name); 628 break; 629 } 630 } 631 } 632 633 static int 634 powerpc_vpadtl_synth_events(struct powerpc_vpadtl *vpa, struct perf_session *session) 635 { 636 struct evlist *evlist = session->evlist; 637 struct evsel *evsel; 638 struct perf_event_attr attr; 639 bool found = false; 640 u64 id; 641 int err; 642 643 evlist__for_each_entry(evlist, evsel) { 644 if (strstarts(evsel->name, "vpa_dtl")) { 645 found = true; 646 break; 647 } 648 } 649 650 if (!found) { 651 pr_debug("No selected events with VPA trace data\n"); 652 return 0; 653 } 654 655 memset(&attr, 0, sizeof(struct perf_event_attr)); 656 attr.size = sizeof(struct perf_event_attr); 657 attr.sample_type = evsel->core.attr.sample_type; 658 attr.sample_id_all = evsel->core.attr.sample_id_all; 659 attr.type = PERF_TYPE_SYNTH; 660 attr.config = PERF_SYNTH_POWERPC_VPA_DTL; 661 662 /* create new id val to be a fixed offset from evsel id */ 663 id = auxtrace_synth_id_range_start(evsel); 664 665 err = perf_session__deliver_synth_attr_event(session, &attr, id); 666 if (err) 667 return err; 668 669 vpa->sample_id = id; 670 set_event_name(evlist, id, "vpa-dtl"); 671 672 return 0; 673 } 674 675 /* 676 * Process the PERF_RECORD_AUXTRACE_INFO records and setup 677 * the infrastructure to process auxtrace events. PERF_RECORD_AUXTRACE_INFO 678 * is processed first since it is of type perf_user_event_type. 679 * Initialise the aux buffer queues using auxtrace_queues__init(). 680 * auxtrace_queue is created for each CPU. 681 */ 682 int powerpc_vpadtl_process_auxtrace_info(union perf_event *event, 683 struct perf_session *session) 684 { 685 struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; 686 size_t min_sz = sizeof(u64) * POWERPC_VPADTL_TYPE; 687 struct powerpc_vpadtl *vpa; 688 int err; 689 690 if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) + 691 min_sz) 692 return -EINVAL; 693 694 vpa = zalloc(sizeof(struct powerpc_vpadtl)); 695 if (!vpa) 696 return -ENOMEM; 697 698 err = auxtrace_queues__init(&vpa->queues); 699 if (err) 700 goto err_free; 701 702 vpa->session = session; 703 vpa->machine = &session->machines.host; /* No kvm support */ 704 vpa->auxtrace_type = auxtrace_info->type; 705 vpa->pmu_type = auxtrace_info->priv[POWERPC_VPADTL_TYPE]; 706 707 vpa->auxtrace.process_event = powerpc_vpadtl_process_event; 708 vpa->auxtrace.process_auxtrace_event = powerpc_vpadtl_process_auxtrace_event; 709 vpa->auxtrace.flush_events = powerpc_vpadtl_flush; 710 vpa->auxtrace.free_events = powerpc_vpadtl_free_events; 711 vpa->auxtrace.free = powerpc_vpadtl_free; 712 session->auxtrace = &vpa->auxtrace; 713 714 powerpc_vpadtl_print_info(&auxtrace_info->priv[0]); 715 716 if (dump_trace) 717 return 0; 718 719 err = powerpc_vpadtl_synth_events(vpa, session); 720 if (err) 721 goto err_free_queues; 722 723 err = auxtrace_queues__process_index(&vpa->queues, session); 724 if (err) 725 goto err_free_queues; 726 727 return 0; 728 729 err_free_queues: 730 auxtrace_queues__free(&vpa->queues); 731 session->auxtrace = NULL; 732 733 err_free: 734 free(vpa); 735 return err; 736 } 737