diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/perf/util/cs-etm-decoder/cs-etm-decoder.c | 65 | ||||
| -rw-r--r-- | tools/perf/util/cs-etm-decoder/cs-etm-decoder.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/cs-etm.c | 434 |
3 files changed, 436 insertions, 64 deletions
diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c index 1fb01849f1c7..8ff69dfd725a 100644 --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c | |||
| @@ -78,6 +78,8 @@ int cs_etm_decoder__reset(struct cs_etm_decoder *decoder) | |||
| 78 | { | 78 | { |
| 79 | ocsd_datapath_resp_t dp_ret; | 79 | ocsd_datapath_resp_t dp_ret; |
| 80 | 80 | ||
| 81 | decoder->prev_return = OCSD_RESP_CONT; | ||
| 82 | |||
| 81 | dp_ret = ocsd_dt_process_data(decoder->dcd_tree, OCSD_OP_RESET, | 83 | dp_ret = ocsd_dt_process_data(decoder->dcd_tree, OCSD_OP_RESET, |
| 82 | 0, 0, NULL, NULL); | 84 | 0, 0, NULL, NULL); |
| 83 | if (OCSD_DATA_RESP_IS_FATAL(dp_ret)) | 85 | if (OCSD_DATA_RESP_IS_FATAL(dp_ret)) |
| @@ -253,16 +255,16 @@ static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder *decoder) | |||
| 253 | decoder->packet_count = 0; | 255 | decoder->packet_count = 0; |
| 254 | for (i = 0; i < MAX_BUFFER; i++) { | 256 | for (i = 0; i < MAX_BUFFER; i++) { |
| 255 | decoder->packet_buffer[i].start_addr = 0xdeadbeefdeadbeefUL; | 257 | decoder->packet_buffer[i].start_addr = 0xdeadbeefdeadbeefUL; |
| 256 | decoder->packet_buffer[i].end_addr = 0xdeadbeefdeadbeefUL; | 258 | decoder->packet_buffer[i].end_addr = 0xdeadbeefdeadbeefUL; |
| 257 | decoder->packet_buffer[i].exc = false; | 259 | decoder->packet_buffer[i].last_instr_taken_branch = false; |
| 258 | decoder->packet_buffer[i].exc_ret = false; | 260 | decoder->packet_buffer[i].exc = false; |
| 259 | decoder->packet_buffer[i].cpu = INT_MIN; | 261 | decoder->packet_buffer[i].exc_ret = false; |
| 262 | decoder->packet_buffer[i].cpu = INT_MIN; | ||
| 260 | } | 263 | } |
| 261 | } | 264 | } |
| 262 | 265 | ||
| 263 | static ocsd_datapath_resp_t | 266 | static ocsd_datapath_resp_t |
| 264 | cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder, | 267 | cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder, |
| 265 | const ocsd_generic_trace_elem *elem, | ||
| 266 | const u8 trace_chan_id, | 268 | const u8 trace_chan_id, |
| 267 | enum cs_etm_sample_type sample_type) | 269 | enum cs_etm_sample_type sample_type) |
| 268 | { | 270 | { |
| @@ -278,18 +280,16 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder, | |||
| 278 | return OCSD_RESP_FATAL_SYS_ERR; | 280 | return OCSD_RESP_FATAL_SYS_ERR; |
| 279 | 281 | ||
| 280 | et = decoder->tail; | 282 | et = decoder->tail; |
| 283 | et = (et + 1) & (MAX_BUFFER - 1); | ||
| 284 | decoder->tail = et; | ||
| 285 | decoder->packet_count++; | ||
| 286 | |||
| 281 | decoder->packet_buffer[et].sample_type = sample_type; | 287 | decoder->packet_buffer[et].sample_type = sample_type; |
| 282 | decoder->packet_buffer[et].start_addr = elem->st_addr; | ||
| 283 | decoder->packet_buffer[et].end_addr = elem->en_addr; | ||
| 284 | decoder->packet_buffer[et].exc = false; | 288 | decoder->packet_buffer[et].exc = false; |
| 285 | decoder->packet_buffer[et].exc_ret = false; | 289 | decoder->packet_buffer[et].exc_ret = false; |
| 286 | decoder->packet_buffer[et].cpu = *((int *)inode->priv); | 290 | decoder->packet_buffer[et].cpu = *((int *)inode->priv); |
| 287 | 291 | decoder->packet_buffer[et].start_addr = 0xdeadbeefdeadbeefUL; | |
| 288 | /* Wrap around if need be */ | 292 | decoder->packet_buffer[et].end_addr = 0xdeadbeefdeadbeefUL; |
| 289 | et = (et + 1) & (MAX_BUFFER - 1); | ||
| 290 | |||
| 291 | decoder->tail = et; | ||
| 292 | decoder->packet_count++; | ||
| 293 | 293 | ||
| 294 | if (decoder->packet_count == MAX_BUFFER - 1) | 294 | if (decoder->packet_count == MAX_BUFFER - 1) |
| 295 | return OCSD_RESP_WAIT; | 295 | return OCSD_RESP_WAIT; |
| @@ -297,6 +297,40 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder, | |||
| 297 | return OCSD_RESP_CONT; | 297 | return OCSD_RESP_CONT; |
| 298 | } | 298 | } |
| 299 | 299 | ||
| 300 | static ocsd_datapath_resp_t | ||
| 301 | cs_etm_decoder__buffer_range(struct cs_etm_decoder *decoder, | ||
| 302 | const ocsd_generic_trace_elem *elem, | ||
| 303 | const uint8_t trace_chan_id) | ||
| 304 | { | ||
| 305 | int ret = 0; | ||
| 306 | struct cs_etm_packet *packet; | ||
| 307 | |||
| 308 | ret = cs_etm_decoder__buffer_packet(decoder, trace_chan_id, | ||
| 309 | CS_ETM_RANGE); | ||
| 310 | if (ret != OCSD_RESP_CONT && ret != OCSD_RESP_WAIT) | ||
| 311 | return ret; | ||
| 312 | |||
| 313 | packet = &decoder->packet_buffer[decoder->tail]; | ||
| 314 | |||
| 315 | packet->start_addr = elem->st_addr; | ||
| 316 | packet->end_addr = elem->en_addr; | ||
| 317 | switch (elem->last_i_type) { | ||
| 318 | case OCSD_INSTR_BR: | ||
| 319 | case OCSD_INSTR_BR_INDIRECT: | ||
| 320 | packet->last_instr_taken_branch = elem->last_instr_exec; | ||
| 321 | break; | ||
| 322 | case OCSD_INSTR_ISB: | ||
| 323 | case OCSD_INSTR_DSB_DMB: | ||
| 324 | case OCSD_INSTR_OTHER: | ||
| 325 | default: | ||
| 326 | packet->last_instr_taken_branch = false; | ||
| 327 | break; | ||
| 328 | } | ||
| 329 | |||
| 330 | return ret; | ||
| 331 | |||
| 332 | } | ||
| 333 | |||
| 300 | static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer( | 334 | static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer( |
| 301 | const void *context, | 335 | const void *context, |
| 302 | const ocsd_trc_index_t indx __maybe_unused, | 336 | const ocsd_trc_index_t indx __maybe_unused, |
| @@ -316,9 +350,8 @@ static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer( | |||
| 316 | decoder->trace_on = true; | 350 | decoder->trace_on = true; |
| 317 | break; | 351 | break; |
| 318 | case OCSD_GEN_TRC_ELEM_INSTR_RANGE: | 352 | case OCSD_GEN_TRC_ELEM_INSTR_RANGE: |
| 319 | resp = cs_etm_decoder__buffer_packet(decoder, elem, | 353 | resp = cs_etm_decoder__buffer_range(decoder, elem, |
| 320 | trace_chan_id, | 354 | trace_chan_id); |
| 321 | CS_ETM_RANGE); | ||
| 322 | break; | 355 | break; |
| 323 | case OCSD_GEN_TRC_ELEM_EXCEPTION: | 356 | case OCSD_GEN_TRC_ELEM_EXCEPTION: |
| 324 | decoder->packet_buffer[decoder->tail].exc = true; | 357 | decoder->packet_buffer[decoder->tail].exc = true; |
diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h index 3d2e6205d186..a4fdd285b145 100644 --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h | |||
| @@ -30,6 +30,7 @@ struct cs_etm_packet { | |||
| 30 | enum cs_etm_sample_type sample_type; | 30 | enum cs_etm_sample_type sample_type; |
| 31 | u64 start_addr; | 31 | u64 start_addr; |
| 32 | u64 end_addr; | 32 | u64 end_addr; |
| 33 | u8 last_instr_taken_branch; | ||
| 33 | u8 exc; | 34 | u8 exc; |
| 34 | u8 exc_ret; | 35 | u8 exc_ret; |
| 35 | int cpu; | 36 | int cpu; |
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index f2c98774e665..6e595d96c04d 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c | |||
| @@ -32,6 +32,14 @@ | |||
| 32 | 32 | ||
| 33 | #define MAX_TIMESTAMP (~0ULL) | 33 | #define MAX_TIMESTAMP (~0ULL) |
| 34 | 34 | ||
| 35 | /* | ||
| 36 | * A64 instructions are always 4 bytes | ||
| 37 | * | ||
| 38 | * Only A64 is supported, so can use this constant for converting between | ||
| 39 | * addresses and instruction counts, calculting offsets etc | ||
| 40 | */ | ||
| 41 | #define A64_INSTR_SIZE 4 | ||
| 42 | |||
| 35 | struct cs_etm_auxtrace { | 43 | struct cs_etm_auxtrace { |
| 36 | struct auxtrace auxtrace; | 44 | struct auxtrace auxtrace; |
| 37 | struct auxtrace_queues queues; | 45 | struct auxtrace_queues queues; |
| @@ -45,11 +53,15 @@ struct cs_etm_auxtrace { | |||
| 45 | u8 snapshot_mode; | 53 | u8 snapshot_mode; |
| 46 | u8 data_queued; | 54 | u8 data_queued; |
| 47 | u8 sample_branches; | 55 | u8 sample_branches; |
| 56 | u8 sample_instructions; | ||
| 48 | 57 | ||
| 49 | int num_cpu; | 58 | int num_cpu; |
| 50 | u32 auxtrace_type; | 59 | u32 auxtrace_type; |
| 51 | u64 branches_sample_type; | 60 | u64 branches_sample_type; |
| 52 | u64 branches_id; | 61 | u64 branches_id; |
| 62 | u64 instructions_sample_type; | ||
| 63 | u64 instructions_sample_period; | ||
| 64 | u64 instructions_id; | ||
| 53 | u64 **metadata; | 65 | u64 **metadata; |
| 54 | u64 kernel_start; | 66 | u64 kernel_start; |
| 55 | unsigned int pmu_type; | 67 | unsigned int pmu_type; |
| @@ -68,6 +80,12 @@ struct cs_etm_queue { | |||
| 68 | u64 time; | 80 | u64 time; |
| 69 | u64 timestamp; | 81 | u64 timestamp; |
| 70 | u64 offset; | 82 | u64 offset; |
| 83 | u64 period_instructions; | ||
| 84 | struct branch_stack *last_branch; | ||
| 85 | struct branch_stack *last_branch_rb; | ||
| 86 | size_t last_branch_pos; | ||
| 87 | struct cs_etm_packet *prev_packet; | ||
| 88 | struct cs_etm_packet *packet; | ||
| 71 | }; | 89 | }; |
| 72 | 90 | ||
| 73 | static int cs_etm__update_queues(struct cs_etm_auxtrace *etm); | 91 | static int cs_etm__update_queues(struct cs_etm_auxtrace *etm); |
| @@ -180,6 +198,10 @@ static void cs_etm__free_queue(void *priv) | |||
| 180 | thread__zput(etmq->thread); | 198 | thread__zput(etmq->thread); |
| 181 | cs_etm_decoder__free(etmq->decoder); | 199 | cs_etm_decoder__free(etmq->decoder); |
| 182 | zfree(&etmq->event_buf); | 200 | zfree(&etmq->event_buf); |
| 201 | zfree(&etmq->last_branch); | ||
| 202 | zfree(&etmq->last_branch_rb); | ||
| 203 | zfree(&etmq->prev_packet); | ||
| 204 | zfree(&etmq->packet); | ||
| 183 | free(etmq); | 205 | free(etmq); |
| 184 | } | 206 | } |
| 185 | 207 | ||
| @@ -276,11 +298,35 @@ static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm, | |||
| 276 | struct cs_etm_decoder_params d_params; | 298 | struct cs_etm_decoder_params d_params; |
| 277 | struct cs_etm_trace_params *t_params; | 299 | struct cs_etm_trace_params *t_params; |
| 278 | struct cs_etm_queue *etmq; | 300 | struct cs_etm_queue *etmq; |
| 301 | size_t szp = sizeof(struct cs_etm_packet); | ||
| 279 | 302 | ||
| 280 | etmq = zalloc(sizeof(*etmq)); | 303 | etmq = zalloc(sizeof(*etmq)); |
| 281 | if (!etmq) | 304 | if (!etmq) |
| 282 | return NULL; | 305 | return NULL; |
| 283 | 306 | ||
| 307 | etmq->packet = zalloc(szp); | ||
| 308 | if (!etmq->packet) | ||
| 309 | goto out_free; | ||
| 310 | |||
| 311 | if (etm->synth_opts.last_branch || etm->sample_branches) { | ||
| 312 | etmq->prev_packet = zalloc(szp); | ||
| 313 | if (!etmq->prev_packet) | ||
| 314 | goto out_free; | ||
| 315 | } | ||
| 316 | |||
| 317 | if (etm->synth_opts.last_branch) { | ||
| 318 | size_t sz = sizeof(struct branch_stack); | ||
| 319 | |||
| 320 | sz += etm->synth_opts.last_branch_sz * | ||
| 321 | sizeof(struct branch_entry); | ||
| 322 | etmq->last_branch = zalloc(sz); | ||
| 323 | if (!etmq->last_branch) | ||
| 324 | goto out_free; | ||
| 325 | etmq->last_branch_rb = zalloc(sz); | ||
| 326 | if (!etmq->last_branch_rb) | ||
| 327 | goto out_free; | ||
| 328 | } | ||
| 329 | |||
| 284 | etmq->event_buf = malloc(PERF_SAMPLE_MAX_SIZE); | 330 | etmq->event_buf = malloc(PERF_SAMPLE_MAX_SIZE); |
| 285 | if (!etmq->event_buf) | 331 | if (!etmq->event_buf) |
| 286 | goto out_free; | 332 | goto out_free; |
| @@ -335,6 +381,7 @@ static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm, | |||
| 335 | goto out_free_decoder; | 381 | goto out_free_decoder; |
| 336 | 382 | ||
| 337 | etmq->offset = 0; | 383 | etmq->offset = 0; |
| 384 | etmq->period_instructions = 0; | ||
| 338 | 385 | ||
| 339 | return etmq; | 386 | return etmq; |
| 340 | 387 | ||
| @@ -342,6 +389,10 @@ out_free_decoder: | |||
| 342 | cs_etm_decoder__free(etmq->decoder); | 389 | cs_etm_decoder__free(etmq->decoder); |
| 343 | out_free: | 390 | out_free: |
| 344 | zfree(&etmq->event_buf); | 391 | zfree(&etmq->event_buf); |
| 392 | zfree(&etmq->last_branch); | ||
| 393 | zfree(&etmq->last_branch_rb); | ||
| 394 | zfree(&etmq->prev_packet); | ||
| 395 | zfree(&etmq->packet); | ||
| 345 | free(etmq); | 396 | free(etmq); |
| 346 | 397 | ||
| 347 | return NULL; | 398 | return NULL; |
| @@ -395,6 +446,129 @@ static int cs_etm__update_queues(struct cs_etm_auxtrace *etm) | |||
| 395 | return 0; | 446 | return 0; |
| 396 | } | 447 | } |
| 397 | 448 | ||
| 449 | static inline void cs_etm__copy_last_branch_rb(struct cs_etm_queue *etmq) | ||
| 450 | { | ||
| 451 | struct branch_stack *bs_src = etmq->last_branch_rb; | ||
| 452 | struct branch_stack *bs_dst = etmq->last_branch; | ||
| 453 | size_t nr = 0; | ||
| 454 | |||
| 455 | /* | ||
| 456 | * Set the number of records before early exit: ->nr is used to | ||
| 457 | * determine how many branches to copy from ->entries. | ||
| 458 | */ | ||
| 459 | bs_dst->nr = bs_src->nr; | ||
| 460 | |||
| 461 | /* | ||
| 462 | * Early exit when there is nothing to copy. | ||
| 463 | */ | ||
| 464 | if (!bs_src->nr) | ||
| 465 | return; | ||
| 466 | |||
| 467 | /* | ||
| 468 | * As bs_src->entries is a circular buffer, we need to copy from it in | ||
| 469 | * two steps. First, copy the branches from the most recently inserted | ||
| 470 | * branch ->last_branch_pos until the end of bs_src->entries buffer. | ||
| 471 | */ | ||
| 472 | nr = etmq->etm->synth_opts.last_branch_sz - etmq->last_branch_pos; | ||
| 473 | memcpy(&bs_dst->entries[0], | ||
| 474 | &bs_src->entries[etmq->last_branch_pos], | ||
| 475 | sizeof(struct branch_entry) * nr); | ||
| 476 | |||
| 477 | /* | ||
| 478 | * If we wrapped around at least once, the branches from the beginning | ||
| 479 | * of the bs_src->entries buffer and until the ->last_branch_pos element | ||
| 480 | * are older valid branches: copy them over. The total number of | ||
| 481 | * branches copied over will be equal to the number of branches asked by | ||
| 482 | * the user in last_branch_sz. | ||
| 483 | */ | ||
| 484 | if (bs_src->nr >= etmq->etm->synth_opts.last_branch_sz) { | ||
| 485 | memcpy(&bs_dst->entries[nr], | ||
| 486 | &bs_src->entries[0], | ||
| 487 | sizeof(struct branch_entry) * etmq->last_branch_pos); | ||
| 488 | } | ||
| 489 | } | ||
| 490 | |||
| 491 | static inline void cs_etm__reset_last_branch_rb(struct cs_etm_queue *etmq) | ||
| 492 | { | ||
| 493 | etmq->last_branch_pos = 0; | ||
| 494 | etmq->last_branch_rb->nr = 0; | ||
| 495 | } | ||
| 496 | |||
| 497 | static inline u64 cs_etm__last_executed_instr(struct cs_etm_packet *packet) | ||
| 498 | { | ||
| 499 | /* | ||
| 500 | * The packet records the execution range with an exclusive end address | ||
| 501 | * | ||
| 502 | * A64 instructions are constant size, so the last executed | ||
| 503 | * instruction is A64_INSTR_SIZE before the end address | ||
| 504 | * Will need to do instruction level decode for T32 instructions as | ||
| 505 | * they can be variable size (not yet supported). | ||
| 506 | */ | ||
| 507 | return packet->end_addr - A64_INSTR_SIZE; | ||
| 508 | } | ||
| 509 | |||
| 510 | static inline u64 cs_etm__instr_count(const struct cs_etm_packet *packet) | ||
| 511 | { | ||
| 512 | /* | ||
| 513 | * Only A64 instructions are currently supported, so can get | ||
| 514 | * instruction count by dividing. | ||
| 515 | * Will need to do instruction level decode for T32 instructions as | ||
| 516 | * they can be variable size (not yet supported). | ||
| 517 | */ | ||
| 518 | return (packet->end_addr - packet->start_addr) / A64_INSTR_SIZE; | ||
| 519 | } | ||
| 520 | |||
| 521 | static inline u64 cs_etm__instr_addr(const struct cs_etm_packet *packet, | ||
| 522 | u64 offset) | ||
| 523 | { | ||
| 524 | /* | ||
| 525 | * Only A64 instructions are currently supported, so can get | ||
| 526 | * instruction address by muliplying. | ||
| 527 | * Will need to do instruction level decode for T32 instructions as | ||
| 528 | * they can be variable size (not yet supported). | ||
| 529 | */ | ||
| 530 | return packet->start_addr + offset * A64_INSTR_SIZE; | ||
| 531 | } | ||
| 532 | |||
| 533 | static void cs_etm__update_last_branch_rb(struct cs_etm_queue *etmq) | ||
| 534 | { | ||
| 535 | struct branch_stack *bs = etmq->last_branch_rb; | ||
| 536 | struct branch_entry *be; | ||
| 537 | |||
| 538 | /* | ||
| 539 | * The branches are recorded in a circular buffer in reverse | ||
| 540 | * chronological order: we start recording from the last element of the | ||
| 541 | * buffer down. After writing the first element of the stack, move the | ||
| 542 | * insert position back to the end of the buffer. | ||
| 543 | */ | ||
| 544 | if (!etmq->last_branch_pos) | ||
| 545 | etmq->last_branch_pos = etmq->etm->synth_opts.last_branch_sz; | ||
| 546 | |||
| 547 | etmq->last_branch_pos -= 1; | ||
| 548 | |||
| 549 | be = &bs->entries[etmq->last_branch_pos]; | ||
| 550 | be->from = cs_etm__last_executed_instr(etmq->prev_packet); | ||
| 551 | be->to = etmq->packet->start_addr; | ||
| 552 | /* No support for mispredict */ | ||
| 553 | be->flags.mispred = 0; | ||
| 554 | be->flags.predicted = 1; | ||
| 555 | |||
| 556 | /* | ||
| 557 | * Increment bs->nr until reaching the number of last branches asked by | ||
| 558 | * the user on the command line. | ||
| 559 | */ | ||
| 560 | if (bs->nr < etmq->etm->synth_opts.last_branch_sz) | ||
| 561 | bs->nr += 1; | ||
| 562 | } | ||
| 563 | |||
| 564 | static int cs_etm__inject_event(union perf_event *event, | ||
| 565 | struct perf_sample *sample, u64 type) | ||
| 566 | { | ||
| 567 | event->header.size = perf_event__sample_event_size(sample, type, 0); | ||
| 568 | return perf_event__synthesize_sample(event, type, 0, sample); | ||
| 569 | } | ||
| 570 | |||
| 571 | |||
| 398 | static int | 572 | static int |
| 399 | cs_etm__get_trace(struct cs_etm_buffer *buff, struct cs_etm_queue *etmq) | 573 | cs_etm__get_trace(struct cs_etm_buffer *buff, struct cs_etm_queue *etmq) |
| 400 | { | 574 | { |
| @@ -459,35 +633,105 @@ static void cs_etm__set_pid_tid_cpu(struct cs_etm_auxtrace *etm, | |||
| 459 | } | 633 | } |
| 460 | } | 634 | } |
| 461 | 635 | ||
| 636 | static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq, | ||
| 637 | u64 addr, u64 period) | ||
| 638 | { | ||
| 639 | int ret = 0; | ||
| 640 | struct cs_etm_auxtrace *etm = etmq->etm; | ||
| 641 | union perf_event *event = etmq->event_buf; | ||
| 642 | struct perf_sample sample = {.ip = 0,}; | ||
| 643 | |||
| 644 | event->sample.header.type = PERF_RECORD_SAMPLE; | ||
| 645 | event->sample.header.misc = PERF_RECORD_MISC_USER; | ||
| 646 | event->sample.header.size = sizeof(struct perf_event_header); | ||
| 647 | |||
| 648 | sample.ip = addr; | ||
| 649 | sample.pid = etmq->pid; | ||
| 650 | sample.tid = etmq->tid; | ||
| 651 | sample.id = etmq->etm->instructions_id; | ||
| 652 | sample.stream_id = etmq->etm->instructions_id; | ||
| 653 | sample.period = period; | ||
| 654 | sample.cpu = etmq->packet->cpu; | ||
| 655 | sample.flags = 0; | ||
| 656 | sample.insn_len = 1; | ||
| 657 | sample.cpumode = event->header.misc; | ||
| 658 | |||
| 659 | if (etm->synth_opts.last_branch) { | ||
| 660 | cs_etm__copy_last_branch_rb(etmq); | ||
| 661 | sample.branch_stack = etmq->last_branch; | ||
| 662 | } | ||
| 663 | |||
| 664 | if (etm->synth_opts.inject) { | ||
| 665 | ret = cs_etm__inject_event(event, &sample, | ||
| 666 | etm->instructions_sample_type); | ||
| 667 | if (ret) | ||
| 668 | return ret; | ||
| 669 | } | ||
| 670 | |||
| 671 | ret = perf_session__deliver_synth_event(etm->session, event, &sample); | ||
| 672 | |||
| 673 | if (ret) | ||
| 674 | pr_err( | ||
| 675 | "CS ETM Trace: failed to deliver instruction event, error %d\n", | ||
| 676 | ret); | ||
| 677 | |||
| 678 | if (etm->synth_opts.last_branch) | ||
| 679 | cs_etm__reset_last_branch_rb(etmq); | ||
| 680 | |||
| 681 | return ret; | ||
| 682 | } | ||
| 683 | |||
| 462 | /* | 684 | /* |
| 463 | * The cs etm packet encodes an instruction range between a branch target | 685 | * The cs etm packet encodes an instruction range between a branch target |
| 464 | * and the next taken branch. Generate sample accordingly. | 686 | * and the next taken branch. Generate sample accordingly. |
| 465 | */ | 687 | */ |
| 466 | static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq, | 688 | static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq) |
| 467 | struct cs_etm_packet *packet) | ||
| 468 | { | 689 | { |
| 469 | int ret = 0; | 690 | int ret = 0; |
| 470 | struct cs_etm_auxtrace *etm = etmq->etm; | 691 | struct cs_etm_auxtrace *etm = etmq->etm; |
| 471 | struct perf_sample sample = {.ip = 0,}; | 692 | struct perf_sample sample = {.ip = 0,}; |
| 472 | union perf_event *event = etmq->event_buf; | 693 | union perf_event *event = etmq->event_buf; |
| 473 | u64 start_addr = packet->start_addr; | 694 | struct dummy_branch_stack { |
| 474 | u64 end_addr = packet->end_addr; | 695 | u64 nr; |
| 696 | struct branch_entry entries; | ||
| 697 | } dummy_bs; | ||
| 475 | 698 | ||
| 476 | event->sample.header.type = PERF_RECORD_SAMPLE; | 699 | event->sample.header.type = PERF_RECORD_SAMPLE; |
| 477 | event->sample.header.misc = PERF_RECORD_MISC_USER; | 700 | event->sample.header.misc = PERF_RECORD_MISC_USER; |
| 478 | event->sample.header.size = sizeof(struct perf_event_header); | 701 | event->sample.header.size = sizeof(struct perf_event_header); |
| 479 | 702 | ||
| 480 | sample.ip = start_addr; | 703 | sample.ip = cs_etm__last_executed_instr(etmq->prev_packet); |
| 481 | sample.pid = etmq->pid; | 704 | sample.pid = etmq->pid; |
| 482 | sample.tid = etmq->tid; | 705 | sample.tid = etmq->tid; |
| 483 | sample.addr = end_addr; | 706 | sample.addr = etmq->packet->start_addr; |
| 484 | sample.id = etmq->etm->branches_id; | 707 | sample.id = etmq->etm->branches_id; |
| 485 | sample.stream_id = etmq->etm->branches_id; | 708 | sample.stream_id = etmq->etm->branches_id; |
| 486 | sample.period = 1; | 709 | sample.period = 1; |
| 487 | sample.cpu = packet->cpu; | 710 | sample.cpu = etmq->packet->cpu; |
| 488 | sample.flags = 0; | 711 | sample.flags = 0; |
| 489 | sample.cpumode = PERF_RECORD_MISC_USER; | 712 | sample.cpumode = PERF_RECORD_MISC_USER; |
| 490 | 713 | ||
| 714 | /* | ||
| 715 | * perf report cannot handle events without a branch stack | ||
| 716 | */ | ||
| 717 | if (etm->synth_opts.last_branch) { | ||
| 718 | dummy_bs = (struct dummy_branch_stack){ | ||
| 719 | .nr = 1, | ||
| 720 | .entries = { | ||
| 721 | .from = sample.ip, | ||
| 722 | .to = sample.addr, | ||
| 723 | }, | ||
| 724 | }; | ||
| 725 | sample.branch_stack = (struct branch_stack *)&dummy_bs; | ||
| 726 | } | ||
| 727 | |||
| 728 | if (etm->synth_opts.inject) { | ||
| 729 | ret = cs_etm__inject_event(event, &sample, | ||
| 730 | etm->branches_sample_type); | ||
| 731 | if (ret) | ||
| 732 | return ret; | ||
| 733 | } | ||
| 734 | |||
| 491 | ret = perf_session__deliver_synth_event(etm->session, event, &sample); | 735 | ret = perf_session__deliver_synth_event(etm->session, event, &sample); |
| 492 | 736 | ||
| 493 | if (ret) | 737 | if (ret) |
| @@ -584,6 +828,24 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm, | |||
| 584 | etm->sample_branches = true; | 828 | etm->sample_branches = true; |
| 585 | etm->branches_sample_type = attr.sample_type; | 829 | etm->branches_sample_type = attr.sample_type; |
| 586 | etm->branches_id = id; | 830 | etm->branches_id = id; |
| 831 | id += 1; | ||
| 832 | attr.sample_type &= ~(u64)PERF_SAMPLE_ADDR; | ||
| 833 | } | ||
| 834 | |||
| 835 | if (etm->synth_opts.last_branch) | ||
| 836 | attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; | ||
| 837 | |||
| 838 | if (etm->synth_opts.instructions) { | ||
| 839 | attr.config = PERF_COUNT_HW_INSTRUCTIONS; | ||
| 840 | attr.sample_period = etm->synth_opts.period; | ||
| 841 | etm->instructions_sample_period = attr.sample_period; | ||
| 842 | err = cs_etm__synth_event(session, &attr, id); | ||
| 843 | if (err) | ||
| 844 | return err; | ||
| 845 | etm->sample_instructions = true; | ||
| 846 | etm->instructions_sample_type = attr.sample_type; | ||
| 847 | etm->instructions_id = id; | ||
| 848 | id += 1; | ||
| 587 | } | 849 | } |
| 588 | 850 | ||
| 589 | return 0; | 851 | return 0; |
| @@ -591,20 +853,68 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm, | |||
| 591 | 853 | ||
| 592 | static int cs_etm__sample(struct cs_etm_queue *etmq) | 854 | static int cs_etm__sample(struct cs_etm_queue *etmq) |
| 593 | { | 855 | { |
| 856 | struct cs_etm_auxtrace *etm = etmq->etm; | ||
| 857 | struct cs_etm_packet *tmp; | ||
| 594 | int ret; | 858 | int ret; |
| 595 | struct cs_etm_packet packet; | 859 | u64 instrs_executed; |
| 596 | 860 | ||
| 597 | while (1) { | 861 | instrs_executed = cs_etm__instr_count(etmq->packet); |
| 598 | ret = cs_etm_decoder__get_packet(etmq->decoder, &packet); | 862 | etmq->period_instructions += instrs_executed; |
| 599 | if (ret <= 0) | 863 | |
| 864 | /* | ||
| 865 | * Record a branch when the last instruction in | ||
| 866 | * PREV_PACKET is a branch. | ||
| 867 | */ | ||
| 868 | if (etm->synth_opts.last_branch && | ||
| 869 | etmq->prev_packet && | ||
| 870 | etmq->prev_packet->last_instr_taken_branch) | ||
| 871 | cs_etm__update_last_branch_rb(etmq); | ||
| 872 | |||
| 873 | if (etm->sample_instructions && | ||
| 874 | etmq->period_instructions >= etm->instructions_sample_period) { | ||
| 875 | /* | ||
| 876 | * Emit instruction sample periodically | ||
| 877 | * TODO: allow period to be defined in cycles and clock time | ||
| 878 | */ | ||
| 879 | |||
| 880 | /* Get number of instructions executed after the sample point */ | ||
| 881 | u64 instrs_over = etmq->period_instructions - | ||
| 882 | etm->instructions_sample_period; | ||
| 883 | |||
| 884 | /* | ||
| 885 | * Calculate the address of the sampled instruction (-1 as | ||
| 886 | * sample is reported as though instruction has just been | ||
| 887 | * executed, but PC has not advanced to next instruction) | ||
| 888 | */ | ||
| 889 | u64 offset = (instrs_executed - instrs_over - 1); | ||
| 890 | u64 addr = cs_etm__instr_addr(etmq->packet, offset); | ||
| 891 | |||
| 892 | ret = cs_etm__synth_instruction_sample( | ||
| 893 | etmq, addr, etm->instructions_sample_period); | ||
| 894 | if (ret) | ||
| 895 | return ret; | ||
| 896 | |||
| 897 | /* Carry remaining instructions into next sample period */ | ||
| 898 | etmq->period_instructions = instrs_over; | ||
| 899 | } | ||
| 900 | |||
| 901 | if (etm->sample_branches && | ||
| 902 | etmq->prev_packet && | ||
| 903 | etmq->prev_packet->sample_type == CS_ETM_RANGE && | ||
| 904 | etmq->prev_packet->last_instr_taken_branch) { | ||
| 905 | ret = cs_etm__synth_branch_sample(etmq); | ||
| 906 | if (ret) | ||
| 600 | return ret; | 907 | return ret; |
| 908 | } | ||
| 601 | 909 | ||
| 910 | if (etm->sample_branches || etm->synth_opts.last_branch) { | ||
| 602 | /* | 911 | /* |
| 603 | * If the packet contains an instruction range, generate an | 912 | * Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for |
| 604 | * instruction sequence event. | 913 | * the next incoming packet. |
| 605 | */ | 914 | */ |
| 606 | if (packet.sample_type & CS_ETM_RANGE) | 915 | tmp = etmq->packet; |
| 607 | cs_etm__synth_branch_sample(etmq, &packet); | 916 | etmq->packet = etmq->prev_packet; |
| 917 | etmq->prev_packet = tmp; | ||
| 608 | } | 918 | } |
| 609 | 919 | ||
| 610 | return 0; | 920 | return 0; |
| @@ -621,45 +931,73 @@ static int cs_etm__run_decoder(struct cs_etm_queue *etmq) | |||
| 621 | etm->kernel_start = machine__kernel_start(etm->machine); | 931 | etm->kernel_start = machine__kernel_start(etm->machine); |
| 622 | 932 | ||
| 623 | /* Go through each buffer in the queue and decode them one by one */ | 933 | /* Go through each buffer in the queue and decode them one by one */ |
| 624 | more: | 934 | while (1) { |
| 625 | buffer_used = 0; | 935 | buffer_used = 0; |
| 626 | memset(&buffer, 0, sizeof(buffer)); | 936 | memset(&buffer, 0, sizeof(buffer)); |
| 627 | err = cs_etm__get_trace(&buffer, etmq); | 937 | err = cs_etm__get_trace(&buffer, etmq); |
| 628 | if (err <= 0) | 938 | if (err <= 0) |
| 629 | return err; | 939 | return err; |
| 630 | /* | 940 | /* |
| 631 | * We cannot assume consecutive blocks in the data file are contiguous, | 941 | * We cannot assume consecutive blocks in the data file are |
| 632 | * reset the decoder to force re-sync. | 942 | * contiguous, reset the decoder to force re-sync. |
| 633 | */ | 943 | */ |
| 634 | err = cs_etm_decoder__reset(etmq->decoder); | 944 | err = cs_etm_decoder__reset(etmq->decoder); |
| 635 | if (err != 0) | 945 | if (err != 0) |
| 636 | return err; | ||
| 637 | |||
| 638 | /* Run trace decoder until buffer consumed or end of trace */ | ||
| 639 | do { | ||
| 640 | processed = 0; | ||
| 641 | |||
| 642 | err = cs_etm_decoder__process_data_block( | ||
| 643 | etmq->decoder, | ||
| 644 | etmq->offset, | ||
| 645 | &buffer.buf[buffer_used], | ||
| 646 | buffer.len - buffer_used, | ||
| 647 | &processed); | ||
| 648 | |||
| 649 | if (err) | ||
| 650 | return err; | 946 | return err; |
| 651 | 947 | ||
| 652 | etmq->offset += processed; | 948 | /* Run trace decoder until buffer consumed or end of trace */ |
| 653 | buffer_used += processed; | 949 | do { |
| 950 | processed = 0; | ||
| 951 | err = cs_etm_decoder__process_data_block( | ||
| 952 | etmq->decoder, | ||
| 953 | etmq->offset, | ||
| 954 | &buffer.buf[buffer_used], | ||
| 955 | buffer.len - buffer_used, | ||
| 956 | &processed); | ||
| 957 | if (err) | ||
| 958 | return err; | ||
| 959 | |||
| 960 | etmq->offset += processed; | ||
| 961 | buffer_used += processed; | ||
| 962 | |||
| 963 | /* Process each packet in this chunk */ | ||
| 964 | while (1) { | ||
| 965 | err = cs_etm_decoder__get_packet(etmq->decoder, | ||
| 966 | etmq->packet); | ||
| 967 | if (err <= 0) | ||
| 968 | /* | ||
| 969 | * Stop processing this chunk on | ||
| 970 | * end of data or error | ||
| 971 | */ | ||
| 972 | break; | ||
| 973 | |||
| 974 | /* | ||
| 975 | * If the packet contains an instruction | ||
| 976 | * range, generate instruction sequence | ||
| 977 | * events. | ||
| 978 | */ | ||
| 979 | if (etmq->packet->sample_type & CS_ETM_RANGE) | ||
| 980 | err = cs_etm__sample(etmq); | ||
| 981 | } | ||
| 982 | } while (buffer.len > buffer_used); | ||
| 654 | 983 | ||
| 655 | /* | 984 | /* |
| 656 | * Nothing to do with an error condition, let's hope the next | 985 | * Generate a last branch event for the branches left in |
| 657 | * chunk will be better. | 986 | * the circular buffer at the end of the trace. |
| 658 | */ | 987 | */ |
| 659 | err = cs_etm__sample(etmq); | 988 | if (etm->sample_instructions && |
| 660 | } while (buffer.len > buffer_used); | 989 | etmq->etm->synth_opts.last_branch) { |
| 990 | struct branch_stack *bs = etmq->last_branch_rb; | ||
| 991 | struct branch_entry *be = | ||
| 992 | &bs->entries[etmq->last_branch_pos]; | ||
| 993 | |||
| 994 | err = cs_etm__synth_instruction_sample( | ||
| 995 | etmq, be->to, etmq->period_instructions); | ||
| 996 | if (err) | ||
| 997 | return err; | ||
| 998 | } | ||
| 661 | 999 | ||
| 662 | goto more; | 1000 | } |
| 663 | 1001 | ||
| 664 | return err; | 1002 | return err; |
| 665 | } | 1003 | } |
