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

perf sample: Make user_regs and intr_regs optional

The struct dump_regs contains 512 bytes of cache_regs, meaning the two
values in perf_sample contribute 1088 bytes of its total 1384 bytes
size. Initializing this much memory has a cost reported by Tavian
Barnes <tavianator@tavianator.com> as about 2.5% when running `perf
script --itrace=i0`:
https://lore.kernel.org/lkml/d841b97b3ad2ca8bcab07e4293375fb7c32dfce7.1736618095.git.tavianator@tavianator.com/

Adrian Hunter <adrian.hunter@intel.com> replied that the zero
initialization was necessary and couldn't simply be removed.

This patch aims to strike a middle ground of still zeroing the
perf_sample, but removing 79% of its size by make user_regs and
intr_regs optional pointers to zalloc-ed memory. To support the
allocation accessors are created for user_regs and intr_regs. To
support correct cleanup perf_sample__init and perf_sample__exit
functions are created and added throughout the code base.

Signed-off-by: Ian Rogers <irogers@google.com>
Link: https://lore.kernel.org/r/20250113194345.1537821-1-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

authored by

Ian Rogers and committed by
Namhyung Kim
dc6d2bc2 08d9e883

+448 -191
+1 -1
tools/perf/arch/x86/tests/dwarf-unwind.c
··· 53 53 int test__arch_unwind_sample(struct perf_sample *sample, 54 54 struct thread *thread) 55 55 { 56 - struct regs_dump *regs = &sample->user_regs; 56 + struct regs_dump *regs = perf_sample__user_regs(sample); 57 57 u64 *buf; 58 58 59 59 buf = malloc(sizeof(u64) * PERF_REGS_MAX);
+1 -1
tools/perf/arch/x86/util/unwind-libdw.c
··· 8 8 bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg) 9 9 { 10 10 struct unwind_info *ui = arg; 11 - struct regs_dump *user_regs = &ui->sample->user_regs; 11 + struct regs_dump *user_regs = perf_sample__user_regs(ui->sample); 12 12 Dwarf_Word dwarf_regs[17]; 13 13 unsigned nregs; 14 14
+3 -1
tools/perf/builtin-record.c
··· 1917 1917 u16 misc_flag) 1918 1918 { 1919 1919 struct perf_sample_id *sid; 1920 - struct perf_sample sample = {}; 1920 + struct perf_sample sample; 1921 1921 int id_hdr_size; 1922 1922 1923 + perf_sample__init(&sample, /*all=*/true); 1923 1924 lost->lost = lost_count; 1924 1925 if (evsel->core.ids) { 1925 1926 sid = xyarray__entry(evsel->core.sample_id, cpu_idx, thread_idx); ··· 1932 1931 lost->header.size = sizeof(*lost) + id_hdr_size; 1933 1932 lost->header.misc = misc_flag; 1934 1933 record__write(rec, NULL, lost, lost->header.size); 1934 + perf_sample__exit(&sample); 1935 1935 } 1936 1936 1937 1937 static void record__read_lost_samples(struct record *rec)
+8 -2
tools/perf/builtin-script.c
··· 783 783 static int perf_sample__fprintf_iregs(struct perf_sample *sample, 784 784 struct perf_event_attr *attr, const char *arch, FILE *fp) 785 785 { 786 - return perf_sample__fprintf_regs(&sample->intr_regs, 786 + if (!sample->intr_regs) 787 + return 0; 788 + 789 + return perf_sample__fprintf_regs(perf_sample__intr_regs(sample), 787 790 attr->sample_regs_intr, arch, fp); 788 791 } 789 792 790 793 static int perf_sample__fprintf_uregs(struct perf_sample *sample, 791 794 struct perf_event_attr *attr, const char *arch, FILE *fp) 792 795 { 793 - return perf_sample__fprintf_regs(&sample->user_regs, 796 + if (!sample->user_regs) 797 + return 0; 798 + 799 + return perf_sample__fprintf_regs(perf_sample__user_regs(sample), 794 800 attr->sample_regs_user, arch, fp); 795 801 } 796 802
+6 -2
tools/perf/builtin-top.c
··· 1157 1157 return 0; 1158 1158 } 1159 1159 1160 + perf_sample__init(&sample, /*all=*/false); 1160 1161 ret = evlist__parse_sample(evlist, event, &sample); 1161 1162 if (ret) { 1162 1163 pr_err("Can't parse sample, err = %d\n", ret); ··· 1168 1167 assert(evsel != NULL); 1169 1168 1170 1169 if (event->header.type == PERF_RECORD_SAMPLE) { 1171 - if (evswitch__discard(&top->evswitch, evsel)) 1172 - return 0; 1170 + if (evswitch__discard(&top->evswitch, evsel)) { 1171 + ret = 0; 1172 + goto next_event; 1173 + } 1173 1174 ++top->samples; 1174 1175 } 1175 1176 ··· 1222 1219 1223 1220 ret = 0; 1224 1221 next_event: 1222 + perf_sample__exit(&sample); 1225 1223 return ret; 1226 1224 } 1227 1225
+4 -1
tools/perf/builtin-trace.c
··· 4066 4066 { 4067 4067 struct evlist *evlist = trace->evlist; 4068 4068 struct perf_sample sample; 4069 - int err = evlist__parse_sample(evlist, event, &sample); 4069 + int err; 4070 4070 4071 + perf_sample__init(&sample, /*all=*/false); 4072 + err = evlist__parse_sample(evlist, event, &sample); 4071 4073 if (err) 4072 4074 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err); 4073 4075 else 4074 4076 trace__handle_event(trace, event, &sample); 4075 4077 4078 + perf_sample__exit(&sample); 4076 4079 return 0; 4077 4080 } 4078 4081
+9 -3
tools/perf/tests/code-reading.c
··· 479 479 struct thread *thread; 480 480 int ret; 481 481 482 - if (evlist__parse_sample(evlist, event, &sample)) { 482 + perf_sample__init(&sample, /*all=*/false); 483 + ret = evlist__parse_sample(evlist, event, &sample); 484 + if (ret) { 483 485 pr_debug("evlist__parse_sample failed\n"); 484 - return -1; 486 + ret = -1; 487 + goto out; 485 488 } 486 489 487 490 thread = machine__findnew_thread(machine, sample.pid, sample.tid); 488 491 if (!thread) { 489 492 pr_debug("machine__findnew_thread failed\n"); 490 - return -1; 493 + ret = -1; 494 + goto out; 491 495 } 492 496 493 497 ret = read_object_code(sample.ip, READLEN, sample.cpumode, thread, state); 494 498 thread__put(thread); 499 + out: 500 + perf_sample__exit(&sample); 495 501 return ret; 496 502 } 497 503
+3 -3
tools/perf/tests/dwarf-unwind.c
··· 115 115 unsigned long cnt = 0; 116 116 int err = -1; 117 117 118 - memset(&sample, 0, sizeof(sample)); 119 - 118 + perf_sample__init(&sample, /*all=*/true); 120 119 if (test__arch_unwind_sample(&sample, thread)) { 121 120 pr_debug("failed to get unwind sample\n"); 122 121 goto out; ··· 133 134 134 135 out: 135 136 zfree(&sample.user_stack.data); 136 - zfree(&sample.user_regs.regs); 137 + zfree(&sample.user_regs->regs); 138 + perf_sample__exit(&sample); 137 139 return err; 138 140 } 139 141
+3
tools/perf/tests/mmap-basic.c
··· 130 130 goto out_delete_evlist; 131 131 } 132 132 133 + perf_sample__init(&sample, /*all=*/false); 133 134 err = evlist__parse_sample(evlist, event, &sample); 134 135 if (err) { 135 136 pr_err("Can't parse sample, err = %d\n", err); 137 + perf_sample__exit(&sample); 136 138 goto out_delete_evlist; 137 139 } 138 140 139 141 err = -1; 140 142 evsel = evlist__id2evsel(evlist, sample.id); 143 + perf_sample__exit(&sample); 141 144 if (evsel == NULL) { 142 145 pr_debug("event with id %" PRIu64 143 146 " doesn't map to an evsel\n", sample.id);
+3 -1
tools/perf/tests/openat-syscall-tp-fields.c
··· 111 111 continue; 112 112 } 113 113 114 + perf_sample__init(&sample, /*all=*/false); 114 115 err = evsel__parse_sample(evsel, event, &sample); 115 116 if (err) { 116 117 pr_debug("Can't parse sample, err = %d\n", err); 118 + perf_sample__exit(&sample); 117 119 goto out_delete_evlist; 118 120 } 119 121 120 122 tp_flags = evsel__intval(evsel, &sample, "flags"); 121 - 123 + perf_sample__exit(&sample); 122 124 if (flags != tp_flags) { 123 125 pr_debug("%s: Expected flags=%#x, got %#x\n", 124 126 __func__, flags, tp_flags);
+5 -1
tools/perf/tests/parse-no-sample-id-all.c
··· 13 13 static int process_event(struct evlist **pevlist, union perf_event *event) 14 14 { 15 15 struct perf_sample sample; 16 + int ret; 16 17 17 18 if (event->header.type == PERF_RECORD_HEADER_ATTR) { 18 19 if (perf_event__process_attr(NULL, event, pevlist)) { ··· 29 28 if (!*pevlist) 30 29 return -1; 31 30 32 - if (evlist__parse_sample(*pevlist, event, &sample)) { 31 + perf_sample__init(&sample, /*all=*/false); 32 + ret = evlist__parse_sample(*pevlist, event, &sample); 33 + perf_sample__exit(&sample); 34 + if (ret) { 33 35 pr_debug("evlist__parse_sample failed\n"); 34 36 return -1; 35 37 }
+2
tools/perf/tests/perf-record.c
··· 70 70 int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, }; 71 71 char sbuf[STRERR_BUFSIZE]; 72 72 73 + perf_sample__init(&sample, /*all=*/false); 73 74 if (evlist == NULL) /* Fallback for kernels lacking PERF_COUNT_SW_DUMMY */ 74 75 evlist = evlist__new_default(); 75 76 ··· 331 330 out_delete_evlist: 332 331 evlist__delete(evlist); 333 332 out: 333 + perf_sample__exit(&sample); 334 334 if (err == -EACCES) 335 335 return TEST_SKIP; 336 336 if (err < 0 || errs != 0)
+2
tools/perf/tests/perf-time-to-tsc.c
··· 153 153 while ((event = perf_mmap__read_event(&md->core)) != NULL) { 154 154 struct perf_sample sample; 155 155 156 + perf_sample__init(&sample, /*all=*/false); 156 157 if (event->header.type != PERF_RECORD_COMM || 157 158 (pid_t)event->comm.pid != getpid() || 158 159 (pid_t)event->comm.tid != getpid()) ··· 171 170 } 172 171 next_event: 173 172 perf_mmap__consume(&md->core); 173 + perf_sample__exit(&sample); 174 174 } 175 175 perf_mmap__read_done(&md->core); 176 176 }
+34 -24
tools/perf/tests/sample-parsing.c
··· 40 40 #define BS_EXPECTED_LE 0x1aa00000000 41 41 #define FLAG(s) s->branch_stack->entries[i].flags 42 42 43 - static bool samples_same(const struct perf_sample *s1, 44 - const struct perf_sample *s2, 43 + static bool samples_same(struct perf_sample *s1, 44 + struct perf_sample *s2, 45 45 u64 type, u64 read_format, bool needs_swap) 46 46 { 47 47 size_t i; ··· 126 126 } 127 127 128 128 if (type & PERF_SAMPLE_REGS_USER) { 129 - size_t sz = hweight_long(s1->user_regs.mask) * sizeof(u64); 129 + struct regs_dump *s1_regs = perf_sample__user_regs(s1); 130 + struct regs_dump *s2_regs = perf_sample__user_regs(s2); 131 + size_t sz = hweight_long(s1_regs->mask) * sizeof(u64); 130 132 131 - COMP(user_regs.mask); 132 - COMP(user_regs.abi); 133 - if (s1->user_regs.abi && 134 - (!s1->user_regs.regs || !s2->user_regs.regs || 135 - memcmp(s1->user_regs.regs, s2->user_regs.regs, sz))) { 133 + COMP(user_regs->mask); 134 + COMP(user_regs->abi); 135 + if (s1_regs->abi && 136 + (!s1_regs->regs || !s2_regs->regs || 137 + memcmp(s1_regs->regs, s2_regs->regs, sz))) { 136 138 pr_debug("Samples differ at 'user_regs'\n"); 137 139 return false; 138 140 } ··· 159 157 COMP(transaction); 160 158 161 159 if (type & PERF_SAMPLE_REGS_INTR) { 162 - size_t sz = hweight_long(s1->intr_regs.mask) * sizeof(u64); 160 + struct regs_dump *s1_regs = perf_sample__intr_regs(s1); 161 + struct regs_dump *s2_regs = perf_sample__intr_regs(s2); 162 + size_t sz = hweight_long(s1_regs->mask) * sizeof(u64); 163 163 164 - COMP(intr_regs.mask); 165 - COMP(intr_regs.abi); 166 - if (s1->intr_regs.abi && 167 - (!s1->intr_regs.regs || !s2->intr_regs.regs || 168 - memcmp(s1->intr_regs.regs, s2->intr_regs.regs, sz))) { 164 + COMP(intr_regs->mask); 165 + COMP(intr_regs->abi); 166 + if (s1_regs->abi && 167 + (!s1_regs->regs || !s2_regs->regs || 168 + memcmp(s1_regs->regs, s2_regs->regs, sz))) { 169 169 pr_debug("Samples differ at 'intr_regs'\n"); 170 170 return false; 171 171 } ··· 227 223 const u32 raw_data[] = {0x12345678, 0x0a0b0c0d, 0x11020304, 0x05060708, 0 }; 228 224 const u64 data[] = {0x2211443366558877ULL, 0, 0xaabbccddeeff4321ULL}; 229 225 const u64 aux_data[] = {0xa55a, 0, 0xeeddee, 0x0282028202820282}; 226 + struct regs_dump user_regs = { 227 + .abi = PERF_SAMPLE_REGS_ABI_64, 228 + .mask = sample_regs, 229 + .regs = regs, 230 + }; 231 + struct regs_dump intr_regs = { 232 + .abi = PERF_SAMPLE_REGS_ABI_64, 233 + .mask = sample_regs, 234 + .regs = regs, 235 + }; 230 236 struct perf_sample sample = { 231 237 .ip = 101, 232 238 .pid = 102, ··· 255 241 .callchain = &callchain.callchain, 256 242 .no_hw_idx = false, 257 243 .branch_stack = &branch_stack.branch_stack, 258 - .user_regs = { 259 - .abi = PERF_SAMPLE_REGS_ABI_64, 260 - .mask = sample_regs, 261 - .regs = regs, 262 - }, 244 + .user_regs = &user_regs, 263 245 .user_stack = { 264 246 .size = sizeof(data), 265 247 .data = (void *)data, ··· 264 254 .time_enabled = 0x030a59d664fca7deULL, 265 255 .time_running = 0x011b6ae553eb98edULL, 266 256 }, 267 - .intr_regs = { 268 - .abi = PERF_SAMPLE_REGS_ABI_64, 269 - .mask = sample_regs, 270 - .regs = regs, 271 - }, 257 + .intr_regs = &intr_regs, 272 258 .phys_addr = 113, 273 259 .cgroup = 114, 274 260 .data_page_size = 115, ··· 279 273 size_t i, sz, bufsz; 280 274 int err, ret = -1; 281 275 276 + perf_sample__init(&sample_out, /*all=*/false); 277 + perf_sample__init(&sample_out_endian, /*all=*/false); 282 278 if (sample_type & PERF_SAMPLE_REGS_USER) 283 279 evsel.core.attr.sample_regs_user = sample_regs; 284 280 ··· 369 361 ret = 0; 370 362 out_free: 371 363 free(event); 364 + perf_sample__exit(&sample_out_endian); 365 + perf_sample__exit(&sample_out); 372 366 if (ret && read_format) 373 367 pr_debug("read_format %#"PRIx64"\n", read_format); 374 368 return ret;
+3
tools/perf/tests/sw-clock.c
··· 104 104 while ((event = perf_mmap__read_event(&md->core)) != NULL) { 105 105 struct perf_sample sample; 106 106 107 + perf_sample__init(&sample, /*all=*/false); 107 108 if (event->header.type != PERF_RECORD_SAMPLE) 108 109 goto next_event; 109 110 110 111 err = evlist__parse_sample(evlist, event, &sample); 111 112 if (err < 0) { 112 113 pr_debug("Error during parse sample\n"); 114 + perf_sample__exit(&sample); 113 115 goto out_delete_evlist; 114 116 } 115 117 ··· 119 117 nr_samples++; 120 118 next_event: 121 119 perf_mmap__consume(&md->core); 120 + perf_sample__exit(&sample); 122 121 } 123 122 perf_mmap__read_done(&md->core); 124 123
+10 -4
tools/perf/tests/switch-tracking.c
··· 131 131 pid_t next_tid, prev_tid; 132 132 int cpu, err; 133 133 134 + perf_sample__init(&sample, /*all=*/false); 134 135 if (evlist__parse_sample(evlist, event, &sample)) { 135 136 pr_debug("evlist__parse_sample failed\n"); 136 - return -1; 137 + err = -1; 138 + goto out; 137 139 } 138 140 139 141 evsel = evlist__id2evsel(evlist, sample.id); ··· 147 145 cpu, prev_tid, next_tid); 148 146 err = check_cpu(switch_tracking, cpu); 149 147 if (err) 150 - return err; 148 + goto out; 151 149 /* 152 150 * Check for no missing sched_switch events i.e. that the 153 151 * evsel->core.system_wide flag has worked. ··· 155 153 if (switch_tracking->tids[cpu] != -1 && 156 154 switch_tracking->tids[cpu] != prev_tid) { 157 155 pr_debug("Missing sched_switch events\n"); 158 - return -1; 156 + err = -1; 157 + goto out; 159 158 } 160 159 switch_tracking->tids[cpu] = next_tid; 161 160 } ··· 172 169 switch_tracking->cycles_after_comm_4 = 1; 173 170 } 174 171 175 - return 0; 172 + err = 0; 173 + out: 174 + perf_sample__exit(&sample); 175 + return err; 176 176 } 177 177 178 178 static int process_event(struct evlist *evlist, union perf_event *event,
+1
tools/perf/util/Build
··· 67 67 perf-util-y += pstack.o 68 68 perf-util-y += session.o 69 69 perf-util-y += tool.o 70 + perf-util-y += sample.o 70 71 perf-util-y += sample-raw.o 71 72 perf-util-y += s390-sample-raw.o 72 73 perf-util-y += amd-sample-raw.o
+18 -6
tools/perf/util/arm-spe.c
··· 379 379 struct arm_spe *spe = speq->spe; 380 380 struct arm_spe_record *record = &speq->decoder->record; 381 381 union perf_event *event = speq->event_buf; 382 - struct perf_sample sample = { .ip = 0, }; 382 + struct perf_sample sample; 383 + int ret; 383 384 385 + perf_sample__init(&sample, /*all=*/true); 384 386 arm_spe_prep_sample(spe, speq, event, &sample); 385 387 386 388 sample.id = spe_events_id; ··· 392 390 sample.data_src = data_src; 393 391 sample.weight = record->latency; 394 392 395 - return arm_spe_deliver_synth_event(spe, speq, event, &sample); 393 + ret = arm_spe_deliver_synth_event(spe, speq, event, &sample); 394 + perf_sample__exit(&sample); 395 + return ret; 396 396 } 397 397 398 398 static int arm_spe__synth_branch_sample(struct arm_spe_queue *speq, ··· 403 399 struct arm_spe *spe = speq->spe; 404 400 struct arm_spe_record *record = &speq->decoder->record; 405 401 union perf_event *event = speq->event_buf; 406 - struct perf_sample sample = { .ip = 0, }; 402 + struct perf_sample sample; 403 + int ret; 407 404 405 + perf_sample__init(&sample, /*all=*/true); 408 406 arm_spe_prep_sample(spe, speq, event, &sample); 409 407 410 408 sample.id = spe_events_id; ··· 415 409 sample.weight = record->latency; 416 410 sample.flags = speq->flags; 417 411 418 - return arm_spe_deliver_synth_event(spe, speq, event, &sample); 412 + ret = arm_spe_deliver_synth_event(spe, speq, event, &sample); 413 + perf_sample__exit(&sample); 414 + return ret; 419 415 } 420 416 421 417 static int arm_spe__synth_instruction_sample(struct arm_spe_queue *speq, ··· 426 418 struct arm_spe *spe = speq->spe; 427 419 struct arm_spe_record *record = &speq->decoder->record; 428 420 union perf_event *event = speq->event_buf; 429 - struct perf_sample sample = { .ip = 0, }; 421 + struct perf_sample sample; 422 + int ret; 430 423 431 424 /* 432 425 * Handles perf instruction sampling period. ··· 437 428 return 0; 438 429 speq->period_instructions = 0; 439 430 431 + perf_sample__init(&sample, /*all=*/true); 440 432 arm_spe_prep_sample(spe, speq, event, &sample); 441 433 442 434 sample.id = spe_events_id; ··· 449 439 sample.weight = record->latency; 450 440 sample.flags = speq->flags; 451 441 452 - return arm_spe_deliver_synth_event(spe, speq, event, &sample); 442 + ret = arm_spe_deliver_synth_event(spe, speq, event, &sample); 443 + perf_sample__exit(&sample); 444 + return ret; 453 445 } 454 446 455 447 static const struct midr_range common_ds_encoding_cpus[] = {
+18 -11
tools/perf/util/arm64-frame-pointer-unwind-support.c
··· 4 4 #include "event.h" 5 5 #include "perf_regs.h" // SMPL_REG_MASK 6 6 #include "unwind.h" 7 + #include <string.h> 7 8 8 9 #define perf_event_arm_regs perf_event_arm64_regs 9 10 #include "../../arch/arm64/include/uapi/asm/perf_regs.h" ··· 17 16 18 17 static bool get_leaf_frame_caller_enabled(struct perf_sample *sample) 19 18 { 20 - return callchain_param.record_mode == CALLCHAIN_FP && sample->user_regs.regs 21 - && sample->user_regs.mask & SMPL_REG_MASK(PERF_REG_ARM64_LR); 19 + struct regs_dump *regs; 20 + 21 + if (callchain_param.record_mode != CALLCHAIN_FP) 22 + return false; 23 + 24 + regs = perf_sample__user_regs(sample); 25 + return regs->regs && regs->mask & SMPL_REG_MASK(PERF_REG_ARM64_LR); 22 26 } 23 27 24 28 static int add_entry(struct unwind_entry *entry, void *arg) ··· 38 32 { 39 33 int ret; 40 34 struct entries entries = {}; 41 - struct regs_dump old_regs = sample->user_regs; 35 + struct regs_dump old_regs, *regs; 42 36 43 37 if (!get_leaf_frame_caller_enabled(sample)) 44 38 return 0; ··· 48 42 * and set its mask. SP is not used when doing the unwinding but it 49 43 * still needs to be set to prevent failures. 50 44 */ 51 - 52 - if (!(sample->user_regs.mask & SMPL_REG_MASK(PERF_REG_ARM64_PC))) { 53 - sample->user_regs.cache_mask |= SMPL_REG_MASK(PERF_REG_ARM64_PC); 54 - sample->user_regs.cache_regs[PERF_REG_ARM64_PC] = sample->callchain->ips[usr_idx+1]; 45 + regs = perf_sample__user_regs(sample); 46 + memcpy(&old_regs, regs, sizeof(*regs)); 47 + if (!(regs->mask & SMPL_REG_MASK(PERF_REG_ARM64_PC))) { 48 + regs->cache_mask |= SMPL_REG_MASK(PERF_REG_ARM64_PC); 49 + regs->cache_regs[PERF_REG_ARM64_PC] = sample->callchain->ips[usr_idx+1]; 55 50 } 56 51 57 - if (!(sample->user_regs.mask & SMPL_REG_MASK(PERF_REG_ARM64_SP))) { 58 - sample->user_regs.cache_mask |= SMPL_REG_MASK(PERF_REG_ARM64_SP); 59 - sample->user_regs.cache_regs[PERF_REG_ARM64_SP] = 0; 52 + if (!(regs->mask & SMPL_REG_MASK(PERF_REG_ARM64_SP))) { 53 + regs->cache_mask |= SMPL_REG_MASK(PERF_REG_ARM64_SP); 54 + regs->cache_regs[PERF_REG_ARM64_SP] = 0; 60 55 } 61 56 62 57 ret = unwind__get_entries(add_entry, &entries, thread, sample, 2, true); 63 - sample->user_regs = old_regs; 58 + memcpy(regs, &old_regs, sizeof(*regs)); 64 59 65 60 if (ret || entries.length != 2) 66 61 return ret;
+9 -6
tools/perf/util/auxtrace.c
··· 1173 1173 if (!qd->samples || event->header.type != PERF_RECORD_SAMPLE) 1174 1174 return 0; 1175 1175 1176 + perf_sample__init(&sample, /*all=*/false); 1176 1177 err = evlist__parse_sample(session->evlist, event, &sample); 1177 1178 if (err) 1178 - return err; 1179 + goto out; 1179 1180 1180 - if (!sample.aux_sample.size) 1181 - return 0; 1181 + if (sample.aux_sample.size) { 1182 + offset += sample.aux_sample.data - (void *)event; 1182 1183 1183 - offset += sample.aux_sample.data - (void *)event; 1184 - 1185 - return session->auxtrace->queue_data(session, &sample, NULL, offset); 1184 + err = session->auxtrace->queue_data(session, &sample, NULL, offset); 1185 + } 1186 + out: 1187 + perf_sample__exit(&sample); 1188 + return err; 1186 1189 } 1187 1190 1188 1191 int auxtrace_queue_data(struct perf_session *session, bool samples, bool events)
+22 -9
tools/perf/util/cs-etm.c
··· 506 506 evsel = evlist__event2evsel(session->evlist, event); 507 507 if (!evsel) 508 508 return -EINVAL; 509 + perf_sample__init(&sample, /*all=*/false); 509 510 err = evsel__parse_sample(evsel, event, &sample); 510 511 if (err) 511 - return err; 512 + goto out; 512 513 cpu = sample.cpu; 513 514 if (cpu == -1) { 514 515 /* no CPU in the sample - possibly recorded with an old version of perf */ 515 516 pr_err("CS_ETM: no CPU AUX_OUTPUT_HW_ID sample. Use compatible perf to record."); 516 - return -EINVAL; 517 + err = -EINVAL; 518 + goto out; 517 519 } 518 520 519 - if (FIELD_GET(CS_AUX_HW_ID_MINOR_VERSION_MASK, hw_id) == 0) 520 - return cs_etm__process_trace_id_v0(etm, cpu, hw_id); 521 + if (FIELD_GET(CS_AUX_HW_ID_MINOR_VERSION_MASK, hw_id) == 0) { 522 + err = cs_etm__process_trace_id_v0(etm, cpu, hw_id); 523 + goto out; 524 + } 521 525 522 - return cs_etm__process_trace_id_v0_1(etm, cpu, hw_id); 526 + err = cs_etm__process_trace_id_v0_1(etm, cpu, hw_id); 527 + out: 528 + perf_sample__exit(&sample); 529 + return err; 523 530 } 524 531 525 532 void cs_etm__etmq_set_traceid_queue_timestamp(struct cs_etm_queue *etmq, ··· 1567 1560 int ret = 0; 1568 1561 struct cs_etm_auxtrace *etm = etmq->etm; 1569 1562 union perf_event *event = tidq->event_buf; 1570 - struct perf_sample sample = {.ip = 0,}; 1563 + struct perf_sample sample; 1571 1564 1565 + perf_sample__init(&sample, /*all=*/true); 1572 1566 event->sample.header.type = PERF_RECORD_SAMPLE; 1573 1567 event->sample.header.misc = cs_etm__cpu_mode(etmq, addr, tidq->el); 1574 1568 event->sample.header.size = sizeof(struct perf_event_header); ··· 1606 1598 "CS ETM Trace: failed to deliver instruction event, error %d\n", 1607 1599 ret); 1608 1600 1601 + perf_sample__exit(&sample); 1609 1602 return ret; 1610 1603 } 1611 1604 ··· 3160 3151 evsel = evlist__event2evsel(session->evlist, event); 3161 3152 if (!evsel) 3162 3153 return -EINVAL; 3154 + perf_sample__init(&sample, /*all=*/false); 3163 3155 ret = evsel__parse_sample(evsel, event, &sample); 3164 3156 if (ret) 3165 - return ret; 3157 + goto out; 3166 3158 3167 3159 /* 3168 3160 * Loop through the auxtrace index to find the buffer that matches up with this aux event. ··· 3178 3168 * 1 ('not found') 3179 3169 */ 3180 3170 if (ret != 1) 3181 - return ret; 3171 + goto out; 3182 3172 } 3183 3173 } 3184 3174 ··· 3188 3178 */ 3189 3179 pr_err("CS ETM: Couldn't find auxtrace buffer for aux_offset: %#"PRI_lx64 3190 3180 " tid: %d cpu: %d\n", event->aux.aux_offset, sample.tid, sample.cpu); 3191 - return 0; 3181 + ret = 0; 3182 + out: 3183 + perf_sample__exit(&sample); 3184 + return ret; 3192 3185 } 3193 3186 3194 3187 static int cs_etm__queue_aux_records(struct perf_session *session)
+12 -9
tools/perf/util/evsel.c
··· 3174 3174 } 3175 3175 3176 3176 if (type & PERF_SAMPLE_REGS_USER) { 3177 + struct regs_dump *regs = perf_sample__user_regs(data); 3178 + 3177 3179 OVERFLOW_CHECK_u64(array); 3178 - data->user_regs.abi = *array; 3180 + regs->abi = *array; 3179 3181 array++; 3180 3182 3181 - if (data->user_regs.abi) { 3183 + if (regs->abi) { 3182 3184 u64 mask = evsel->core.attr.sample_regs_user; 3183 3185 3184 3186 sz = hweight64(mask) * sizeof(u64); 3185 3187 OVERFLOW_CHECK(array, sz, max_size); 3186 - data->user_regs.mask = mask; 3187 - data->user_regs.regs = (u64 *)array; 3188 + regs->mask = mask; 3189 + regs->regs = (u64 *)array; 3188 3190 array = (void *)array + sz; 3189 3191 } 3190 3192 } ··· 3230 3228 array++; 3231 3229 } 3232 3230 3233 - data->intr_regs.abi = PERF_SAMPLE_REGS_ABI_NONE; 3234 3231 if (type & PERF_SAMPLE_REGS_INTR) { 3232 + struct regs_dump *regs = perf_sample__intr_regs(data); 3233 + 3235 3234 OVERFLOW_CHECK_u64(array); 3236 - data->intr_regs.abi = *array; 3235 + regs->abi = *array; 3237 3236 array++; 3238 3237 3239 - if (data->intr_regs.abi != PERF_SAMPLE_REGS_ABI_NONE) { 3238 + if (regs->abi != PERF_SAMPLE_REGS_ABI_NONE) { 3240 3239 u64 mask = evsel->core.attr.sample_regs_intr; 3241 3240 3242 3241 sz = hweight64(mask) * sizeof(u64); 3243 3242 OVERFLOW_CHECK(array, sz, max_size); 3244 - data->intr_regs.mask = mask; 3245 - data->intr_regs.regs = (u64 *)array; 3243 + regs->mask = mask; 3244 + regs->regs = (u64 *)array; 3246 3245 array = (void *)array + sz; 3247 3246 } 3248 3247 }
+3 -1
tools/perf/util/intel-bts.c
··· 275 275 int ret; 276 276 struct intel_bts *bts = btsq->bts; 277 277 union perf_event event; 278 - struct perf_sample sample = { .ip = 0, }; 278 + struct perf_sample sample; 279 279 280 280 if (bts->synth_opts.initial_skip && 281 281 bts->num_events++ <= bts->synth_opts.initial_skip) 282 282 return 0; 283 283 284 + perf_sample__init(&sample, /*all=*/true); 284 285 sample.ip = le64_to_cpu(branch->from); 285 286 sample.cpumode = intel_bts_cpumode(bts, sample.ip); 286 287 sample.pid = btsq->pid; ··· 313 312 pr_err("Intel BTS: failed to deliver branch event, error %d\n", 314 313 ret); 315 314 315 + perf_sample__exit(&sample); 316 316 return ret; 317 317 } 318 318
+94 -42
tools/perf/util/intel-pt.c
··· 1764 1764 { 1765 1765 struct intel_pt *pt = ptq->pt; 1766 1766 union perf_event *event = ptq->event_buf; 1767 - struct perf_sample sample = { .ip = 0, }; 1767 + struct perf_sample sample; 1768 1768 struct dummy_branch_stack { 1769 1769 u64 nr; 1770 1770 u64 hw_idx; 1771 1771 struct branch_entry entries; 1772 1772 } dummy_bs; 1773 + int ret; 1773 1774 1774 1775 if (pt->branches_filter && !(pt->branches_filter & ptq->flags)) 1775 1776 return 0; ··· 1778 1777 if (intel_pt_skip_event(pt)) 1779 1778 return 0; 1780 1779 1780 + perf_sample__init(&sample, /*all=*/true); 1781 1781 intel_pt_prep_b_sample(pt, ptq, event, &sample); 1782 1782 1783 1783 sample.id = ptq->pt->branches_id; ··· 1808 1806 ptq->last_br_cyc_cnt = ptq->ipc_cyc_cnt; 1809 1807 } 1810 1808 1811 - return intel_pt_deliver_synth_event(pt, event, &sample, 1809 + perf_sample__exit(&sample); 1810 + ret = intel_pt_deliver_synth_event(pt, event, &sample, 1812 1811 pt->branches_sample_type); 1812 + return ret; 1813 1813 } 1814 1814 1815 1815 static void intel_pt_prep_sample(struct intel_pt *pt, ··· 1839 1835 { 1840 1836 struct intel_pt *pt = ptq->pt; 1841 1837 union perf_event *event = ptq->event_buf; 1842 - struct perf_sample sample = { .ip = 0, }; 1838 + struct perf_sample sample; 1839 + int ret; 1843 1840 1844 1841 if (intel_pt_skip_event(pt)) 1845 1842 return 0; 1846 1843 1844 + perf_sample__init(&sample, /*all=*/true); 1847 1845 intel_pt_prep_sample(pt, ptq, event, &sample); 1848 1846 1849 1847 sample.id = ptq->pt->instructions_id; ··· 1865 1859 1866 1860 ptq->last_insn_cnt = ptq->state->tot_insn_cnt; 1867 1861 1868 - return intel_pt_deliver_synth_event(pt, event, &sample, 1869 - pt->instructions_sample_type); 1862 + ret = intel_pt_deliver_synth_event(pt, event, &sample, 1863 + pt->instructions_sample_type); 1864 + perf_sample__exit(&sample); 1865 + return ret; 1870 1866 } 1871 1867 1872 1868 static int intel_pt_synth_cycle_sample(struct intel_pt_queue *ptq) 1873 1869 { 1874 1870 struct intel_pt *pt = ptq->pt; 1875 1871 union perf_event *event = ptq->event_buf; 1876 - struct perf_sample sample = { .ip = 0, }; 1872 + struct perf_sample sample; 1877 1873 u64 period = 0; 1874 + int ret; 1878 1875 1879 1876 if (ptq->sample_ipc) 1880 1877 period = ptq->ipc_cyc_cnt - ptq->last_cy_cyc_cnt; ··· 1885 1876 if (!period || intel_pt_skip_event(pt)) 1886 1877 return 0; 1887 1878 1879 + perf_sample__init(&sample, /*all=*/true); 1888 1880 intel_pt_prep_sample(pt, ptq, event, &sample); 1889 1881 1890 1882 sample.id = ptq->pt->cycles_id; ··· 1897 1887 ptq->last_cy_insn_cnt = ptq->ipc_insn_cnt; 1898 1888 ptq->last_cy_cyc_cnt = ptq->ipc_cyc_cnt; 1899 1889 1900 - return intel_pt_deliver_synth_event(pt, event, &sample, pt->cycles_sample_type); 1890 + ret = intel_pt_deliver_synth_event(pt, event, &sample, pt->cycles_sample_type); 1891 + perf_sample__exit(&sample); 1892 + return ret; 1901 1893 } 1902 1894 1903 1895 static int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq) 1904 1896 { 1905 1897 struct intel_pt *pt = ptq->pt; 1906 1898 union perf_event *event = ptq->event_buf; 1907 - struct perf_sample sample = { .ip = 0, }; 1899 + struct perf_sample sample; 1900 + int ret; 1908 1901 1909 1902 if (intel_pt_skip_event(pt)) 1910 1903 return 0; 1911 1904 1905 + perf_sample__init(&sample, /*all=*/true); 1912 1906 intel_pt_prep_sample(pt, ptq, event, &sample); 1913 1907 1914 1908 sample.id = ptq->pt->transactions_id; 1915 1909 sample.stream_id = ptq->pt->transactions_id; 1916 1910 1917 - return intel_pt_deliver_synth_event(pt, event, &sample, 1918 - pt->transactions_sample_type); 1911 + ret = intel_pt_deliver_synth_event(pt, event, &sample, 1912 + pt->transactions_sample_type); 1913 + perf_sample__exit(&sample); 1914 + return ret; 1919 1915 } 1920 1916 1921 1917 static void intel_pt_prep_p_sample(struct intel_pt *pt, ··· 1969 1953 { 1970 1954 struct intel_pt *pt = ptq->pt; 1971 1955 union perf_event *event = ptq->event_buf; 1972 - struct perf_sample sample = { .ip = 0, }; 1956 + struct perf_sample sample; 1973 1957 struct perf_synth_intel_cbr raw; 1974 1958 u32 flags; 1959 + int ret; 1975 1960 1976 1961 if (intel_pt_skip_cbr_event(pt)) 1977 1962 return 0; 1978 1963 1979 1964 ptq->cbr_seen = ptq->state->cbr; 1980 1965 1966 + perf_sample__init(&sample, /*all=*/true); 1981 1967 intel_pt_prep_p_sample(pt, ptq, event, &sample); 1982 1968 1983 1969 sample.id = ptq->pt->cbr_id; ··· 1993 1975 sample.raw_size = perf_synth__raw_size(raw); 1994 1976 sample.raw_data = perf_synth__raw_data(&raw); 1995 1977 1996 - return intel_pt_deliver_synth_event(pt, event, &sample, 1997 - pt->pwr_events_sample_type); 1978 + ret = intel_pt_deliver_synth_event(pt, event, &sample, 1979 + pt->pwr_events_sample_type); 1980 + perf_sample__exit(&sample); 1981 + return ret; 1998 1982 } 1999 1983 2000 1984 static int intel_pt_synth_psb_sample(struct intel_pt_queue *ptq) 2001 1985 { 2002 1986 struct intel_pt *pt = ptq->pt; 2003 1987 union perf_event *event = ptq->event_buf; 2004 - struct perf_sample sample = { .ip = 0, }; 1988 + struct perf_sample sample; 2005 1989 struct perf_synth_intel_psb raw; 1990 + int ret; 2006 1991 2007 1992 if (intel_pt_skip_event(pt)) 2008 1993 return 0; 2009 1994 1995 + perf_sample__init(&sample, /*all=*/true); 2010 1996 intel_pt_prep_p_sample(pt, ptq, event, &sample); 2011 1997 2012 1998 sample.id = ptq->pt->psb_id; ··· 2023 2001 sample.raw_size = perf_synth__raw_size(raw); 2024 2002 sample.raw_data = perf_synth__raw_data(&raw); 2025 2003 2026 - return intel_pt_deliver_synth_event(pt, event, &sample, 2027 - pt->pwr_events_sample_type); 2004 + ret = intel_pt_deliver_synth_event(pt, event, &sample, 2005 + pt->pwr_events_sample_type); 2006 + perf_sample__exit(&sample); 2007 + return ret; 2028 2008 } 2029 2009 2030 2010 static int intel_pt_synth_mwait_sample(struct intel_pt_queue *ptq) 2031 2011 { 2032 2012 struct intel_pt *pt = ptq->pt; 2033 2013 union perf_event *event = ptq->event_buf; 2034 - struct perf_sample sample = { .ip = 0, }; 2014 + struct perf_sample sample; 2035 2015 struct perf_synth_intel_mwait raw; 2016 + int ret; 2036 2017 2037 2018 if (intel_pt_skip_event(pt)) 2038 2019 return 0; 2039 2020 2021 + perf_sample__init(&sample, /*all=*/true); 2040 2022 intel_pt_prep_p_sample(pt, ptq, event, &sample); 2041 2023 2042 2024 sample.id = ptq->pt->mwait_id; ··· 2052 2026 sample.raw_size = perf_synth__raw_size(raw); 2053 2027 sample.raw_data = perf_synth__raw_data(&raw); 2054 2028 2055 - return intel_pt_deliver_synth_event(pt, event, &sample, 2056 - pt->pwr_events_sample_type); 2029 + ret = intel_pt_deliver_synth_event(pt, event, &sample, 2030 + pt->pwr_events_sample_type); 2031 + perf_sample__exit(&sample); 2032 + return ret; 2057 2033 } 2058 2034 2059 2035 static int intel_pt_synth_pwre_sample(struct intel_pt_queue *ptq) 2060 2036 { 2061 2037 struct intel_pt *pt = ptq->pt; 2062 2038 union perf_event *event = ptq->event_buf; 2063 - struct perf_sample sample = { .ip = 0, }; 2039 + struct perf_sample sample; 2064 2040 struct perf_synth_intel_pwre raw; 2041 + int ret; 2065 2042 2066 2043 if (intel_pt_skip_event(pt)) 2067 2044 return 0; 2068 2045 2046 + perf_sample__init(&sample, /*all=*/true); 2069 2047 intel_pt_prep_p_sample(pt, ptq, event, &sample); 2070 2048 2071 2049 sample.id = ptq->pt->pwre_id; ··· 2081 2051 sample.raw_size = perf_synth__raw_size(raw); 2082 2052 sample.raw_data = perf_synth__raw_data(&raw); 2083 2053 2084 - return intel_pt_deliver_synth_event(pt, event, &sample, 2085 - pt->pwr_events_sample_type); 2054 + ret = intel_pt_deliver_synth_event(pt, event, &sample, 2055 + pt->pwr_events_sample_type); 2056 + perf_sample__exit(&sample); 2057 + return ret; 2086 2058 } 2087 2059 2088 2060 static int intel_pt_synth_exstop_sample(struct intel_pt_queue *ptq) 2089 2061 { 2090 2062 struct intel_pt *pt = ptq->pt; 2091 2063 union perf_event *event = ptq->event_buf; 2092 - struct perf_sample sample = { .ip = 0, }; 2064 + struct perf_sample sample; 2093 2065 struct perf_synth_intel_exstop raw; 2066 + int ret; 2094 2067 2095 2068 if (intel_pt_skip_event(pt)) 2096 2069 return 0; 2097 2070 2071 + perf_sample__init(&sample, /*all=*/true); 2098 2072 intel_pt_prep_p_sample(pt, ptq, event, &sample); 2099 2073 2100 2074 sample.id = ptq->pt->exstop_id; ··· 2110 2076 sample.raw_size = perf_synth__raw_size(raw); 2111 2077 sample.raw_data = perf_synth__raw_data(&raw); 2112 2078 2113 - return intel_pt_deliver_synth_event(pt, event, &sample, 2114 - pt->pwr_events_sample_type); 2079 + ret = intel_pt_deliver_synth_event(pt, event, &sample, 2080 + pt->pwr_events_sample_type); 2081 + perf_sample__exit(&sample); 2082 + return ret; 2115 2083 } 2116 2084 2117 2085 static int intel_pt_synth_pwrx_sample(struct intel_pt_queue *ptq) 2118 2086 { 2119 2087 struct intel_pt *pt = ptq->pt; 2120 2088 union perf_event *event = ptq->event_buf; 2121 - struct perf_sample sample = { .ip = 0, }; 2089 + struct perf_sample sample; 2122 2090 struct perf_synth_intel_pwrx raw; 2091 + int ret; 2123 2092 2124 2093 if (intel_pt_skip_event(pt)) 2125 2094 return 0; 2126 2095 2096 + perf_sample__init(&sample, /*all=*/true); 2127 2097 intel_pt_prep_p_sample(pt, ptq, event, &sample); 2128 2098 2129 2099 sample.id = ptq->pt->pwrx_id; ··· 2139 2101 sample.raw_size = perf_synth__raw_size(raw); 2140 2102 sample.raw_data = perf_synth__raw_data(&raw); 2141 2103 2142 - return intel_pt_deliver_synth_event(pt, event, &sample, 2143 - pt->pwr_events_sample_type); 2104 + ret = intel_pt_deliver_synth_event(pt, event, &sample, 2105 + pt->pwr_events_sample_type); 2106 + perf_sample__exit(&sample); 2107 + return ret; 2144 2108 } 2145 2109 2146 2110 /* ··· 2275 2235 static int intel_pt_do_synth_pebs_sample(struct intel_pt_queue *ptq, struct evsel *evsel, u64 id) 2276 2236 { 2277 2237 const struct intel_pt_blk_items *items = &ptq->state->items; 2278 - struct perf_sample sample = { .ip = 0, }; 2238 + struct perf_sample sample; 2279 2239 union perf_event *event = ptq->event_buf; 2280 2240 struct intel_pt *pt = ptq->pt; 2281 2241 u64 sample_type = evsel->core.attr.sample_type; 2282 2242 u8 cpumode; 2283 - u64 regs[8 * sizeof(sample.intr_regs.mask)]; 2243 + u64 regs[8 * sizeof(sample.intr_regs->mask)]; 2244 + int ret; 2284 2245 2285 2246 if (intel_pt_skip_event(pt)) 2286 2247 return 0; 2287 2248 2249 + perf_sample__init(&sample, /*all=*/true); 2288 2250 intel_pt_prep_a_sample(ptq, event, &sample); 2289 2251 2290 2252 sample.id = id; ··· 2333 2291 items->mask[INTEL_PT_XMM_POS])) { 2334 2292 u64 regs_mask = evsel->core.attr.sample_regs_intr; 2335 2293 u64 *pos; 2294 + struct regs_dump *intr_regs = perf_sample__intr_regs(&sample); 2336 2295 2337 - sample.intr_regs.abi = items->is_32_bit ? 2296 + intr_regs->abi = items->is_32_bit ? 2338 2297 PERF_SAMPLE_REGS_ABI_32 : 2339 2298 PERF_SAMPLE_REGS_ABI_64; 2340 - sample.intr_regs.regs = regs; 2299 + intr_regs->regs = regs; 2341 2300 2342 - pos = intel_pt_add_gp_regs(&sample.intr_regs, regs, items, regs_mask); 2301 + pos = intel_pt_add_gp_regs(intr_regs, regs, items, regs_mask); 2343 2302 2344 - intel_pt_add_xmm(&sample.intr_regs, pos, items, regs_mask); 2303 + intel_pt_add_xmm(intr_regs, pos, items, regs_mask); 2345 2304 } 2346 2305 2347 2306 if (sample_type & PERF_SAMPLE_BRANCH_STACK) { ··· 2404 2361 sample.transaction = txn; 2405 2362 } 2406 2363 2407 - return intel_pt_deliver_synth_event(pt, event, &sample, sample_type); 2364 + ret = intel_pt_deliver_synth_event(pt, event, &sample, sample_type); 2365 + perf_sample__exit(&sample); 2366 + return ret; 2408 2367 } 2409 2368 2410 2369 static int intel_pt_synth_single_pebs_sample(struct intel_pt_queue *ptq) ··· 2452 2407 { 2453 2408 struct intel_pt *pt = ptq->pt; 2454 2409 union perf_event *event = ptq->event_buf; 2455 - struct perf_sample sample = { .ip = 0, }; 2410 + struct perf_sample sample; 2456 2411 struct { 2457 2412 struct perf_synth_intel_evt cfe; 2458 2413 struct perf_synth_intel_evd evd[INTEL_PT_MAX_EVDS]; 2459 2414 } raw; 2460 - int i; 2415 + int i, ret; 2461 2416 2462 2417 if (intel_pt_skip_event(pt)) 2463 2418 return 0; 2464 2419 2420 + perf_sample__init(&sample, /*all=*/true); 2465 2421 intel_pt_prep_p_sample(pt, ptq, event, &sample); 2466 2422 2467 2423 sample.id = ptq->pt->evt_id; ··· 2484 2438 ptq->state->evd_cnt * sizeof(struct perf_synth_intel_evd); 2485 2439 sample.raw_data = perf_synth__raw_data(&raw); 2486 2440 2487 - return intel_pt_deliver_synth_event(pt, event, &sample, 2488 - pt->evt_sample_type); 2441 + ret = intel_pt_deliver_synth_event(pt, event, &sample, 2442 + pt->evt_sample_type); 2443 + perf_sample__exit(&sample); 2444 + return ret; 2489 2445 } 2490 2446 2491 2447 static int intel_pt_synth_iflag_chg_sample(struct intel_pt_queue *ptq) 2492 2448 { 2493 2449 struct intel_pt *pt = ptq->pt; 2494 2450 union perf_event *event = ptq->event_buf; 2495 - struct perf_sample sample = { .ip = 0, }; 2451 + struct perf_sample sample; 2496 2452 struct perf_synth_intel_iflag_chg raw; 2453 + int ret; 2497 2454 2498 2455 if (intel_pt_skip_event(pt)) 2499 2456 return 0; 2500 2457 2458 + perf_sample__init(&sample, /*all=*/true); 2501 2459 intel_pt_prep_p_sample(pt, ptq, event, &sample); 2502 2460 2503 2461 sample.id = ptq->pt->iflag_chg_id; ··· 2521 2471 sample.raw_size = perf_synth__raw_size(raw); 2522 2472 sample.raw_data = perf_synth__raw_data(&raw); 2523 2473 2524 - return intel_pt_deliver_synth_event(pt, event, &sample, 2525 - pt->iflag_chg_sample_type); 2474 + ret = intel_pt_deliver_synth_event(pt, event, &sample, 2475 + pt->iflag_chg_sample_type); 2476 + perf_sample__exit(&sample); 2477 + return ret; 2526 2478 } 2527 2479 2528 2480 static int intel_pt_synth_error(struct intel_pt *pt, int code, int cpu,
+6 -4
tools/perf/util/jitdump.c
··· 516 516 * create pseudo sample to induce dso hit increment 517 517 * use first address as sample address 518 518 */ 519 - memset(&sample, 0, sizeof(sample)); 519 + perf_sample__init(&sample, /*all=*/true); 520 520 sample.cpumode = PERF_RECORD_MISC_USER; 521 521 sample.pid = pid; 522 522 sample.tid = tid; ··· 535 535 build_id__mark_dso_hit(tool, event, &sample, NULL, jd->machine); 536 536 537 537 out: 538 + perf_sample__exit(&sample); 538 539 free(event); 539 540 return ret; 540 541 } ··· 612 611 * create pseudo sample to induce dso hit increment 613 612 * use first address as sample address 614 613 */ 615 - memset(&sample, 0, sizeof(sample)); 614 + perf_sample__init(&sample, /*all=*/true); 616 615 sample.cpumode = PERF_RECORD_MISC_USER; 617 616 sample.pid = pid; 618 617 sample.tid = tid; ··· 621 620 622 621 ret = perf_event__process_mmap2(tool, event, &sample, jd->machine); 623 622 if (ret) 624 - return ret; 623 + goto out; 625 624 626 625 ret = jit_inject_event(jd, event); 627 626 if (!ret) 628 627 build_id__mark_dso_hit(tool, event, &sample, NULL, jd->machine); 629 - 628 + out: 629 + perf_sample__exit(&sample); 630 630 return ret; 631 631 } 632 632
+2 -2
tools/perf/util/machine.c
··· 2909 2909 return 0; 2910 2910 2911 2911 /* Bail out if nothing was captured. */ 2912 - if ((!sample->user_regs.regs) || 2913 - (!sample->user_stack.size)) 2912 + if (!sample->user_regs || !sample->user_regs->regs || 2913 + !sample->user_stack.size) 2914 2914 return 0; 2915 2915 2916 2916 if (!symbols)
+9
tools/perf/util/python.c
··· 270 270 { .name = NULL, }, 271 271 }; 272 272 273 + static void pyrf_sample_event__delete(struct pyrf_event *pevent) 274 + { 275 + perf_sample__exit(&pevent->sample); 276 + Py_TYPE(pevent)->tp_free((PyObject*)pevent); 277 + } 278 + 273 279 static PyObject *pyrf_sample_event__repr(const struct pyrf_event *pevent) 274 280 { 275 281 PyObject *ret; ··· 434 428 pyrf_sample_event__type.tp_new = 435 429 pyrf_context_switch_event__type.tp_new = 436 430 pyrf_throttle_event__type.tp_new = PyType_GenericNew; 431 + 432 + pyrf_sample_event__type.tp_dealloc = (destructor)pyrf_sample_event__delete, 433 + 437 434 err = PyType_Ready(&pyrf_mmap_event__type); 438 435 if (err < 0) 439 436 goto out;
+4 -2
tools/perf/util/s390-cpumsf.c
··· 513 513 .period = 1 514 514 }; 515 515 union perf_event event; 516 + int ret; 516 517 517 518 memset(&event, 0, sizeof(event)); 518 519 if (basic->CL == 1) /* Native LPAR mode */ ··· 537 536 pr_debug4("%s pos:%#zx ip:%#" PRIx64 " P:%d CL:%d pid:%d.%d cpumode:%d cpu:%d\n", 538 537 __func__, pos, sample.ip, basic->P, basic->CL, sample.pid, 539 538 sample.tid, sample.cpumode, sample.cpu); 540 - if (perf_session__deliver_synth_event(sfq->sf->session, &event, 541 - &sample)) { 539 + ret = perf_session__deliver_synth_event(sfq->sf->session, &event, &sample); 540 + perf_sample__exit(&sample); 541 + if (ret) { 542 542 pr_err("s390 Auxiliary Trace: failed to deliver event\n"); 543 543 return false; 544 544 }
+43
tools/perf/util/sample.c
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #include "sample.h" 3 + #include "debug.h" 4 + #include <linux/zalloc.h> 5 + #include <stdlib.h> 6 + #include <string.h> 7 + 8 + void perf_sample__init(struct perf_sample *sample, bool all) 9 + { 10 + if (all) { 11 + memset(sample, 0, sizeof(*sample)); 12 + } else { 13 + sample->user_regs = NULL; 14 + sample->intr_regs = NULL; 15 + } 16 + } 17 + 18 + void perf_sample__exit(struct perf_sample *sample) 19 + { 20 + free(sample->user_regs); 21 + free(sample->intr_regs); 22 + } 23 + 24 + struct regs_dump *perf_sample__user_regs(struct perf_sample *sample) 25 + { 26 + if (!sample->user_regs) { 27 + sample->user_regs = zalloc(sizeof(*sample->user_regs)); 28 + if (!sample->user_regs) 29 + pr_err("Failure to allocate sample user_regs"); 30 + } 31 + return sample->user_regs; 32 + } 33 + 34 + 35 + struct regs_dump *perf_sample__intr_regs(struct perf_sample *sample) 36 + { 37 + if (!sample->intr_regs) { 38 + sample->intr_regs = zalloc(sizeof(*sample->intr_regs)); 39 + if (!sample->intr_regs) 40 + pr_err("Failure to allocate sample intr_regs"); 41 + } 42 + return sample->intr_regs; 43 + }
+7 -2
tools/perf/util/sample.h
··· 114 114 struct ip_callchain *callchain; 115 115 struct branch_stack *branch_stack; 116 116 u64 *branch_stack_cntr; 117 - struct regs_dump user_regs; 118 - struct regs_dump intr_regs; 117 + struct regs_dump *user_regs; 118 + struct regs_dump *intr_regs; 119 119 struct stack_dump user_stack; 120 120 struct sample_read read; 121 121 struct aux_sample aux_sample; 122 122 struct simd_flags simd_flags; 123 123 }; 124 + 125 + void perf_sample__init(struct perf_sample *sample, bool all); 126 + void perf_sample__exit(struct perf_sample *sample); 127 + struct regs_dump *perf_sample__user_regs(struct perf_sample *sample); 128 + struct regs_dump *perf_sample__intr_regs(struct perf_sample *sample); 124 129 125 130 /* 126 131 * raw_data is always 4 bytes from an 8-byte boundary, so subtract 4 to get
+20 -9
tools/perf/util/scripting-engines/trace-event-python.c
··· 745 745 const char *arch = perf_env__arch(evsel__env(evsel)); 746 746 747 747 int size = (__sw_hweight64(attr->sample_regs_intr) * MAX_REG_SIZE) + 1; 748 - char *bf = malloc(size); 749 - if (!bf) 750 - return -1; 748 + char *bf = NULL; 751 749 752 - regs_map(&sample->intr_regs, attr->sample_regs_intr, arch, bf, size); 750 + if (sample->intr_regs) { 751 + bf = malloc(size); 752 + if (!bf) 753 + return -1; 753 754 754 - pydict_set_item_string_decref(dict, "iregs", 755 - _PyUnicode_FromString(bf)); 755 + regs_map(sample->intr_regs, attr->sample_regs_intr, arch, bf, size); 756 756 757 - regs_map(&sample->user_regs, attr->sample_regs_user, arch, bf, size); 757 + pydict_set_item_string_decref(dict, "iregs", 758 + _PyUnicode_FromString(bf)); 759 + } 758 760 759 - pydict_set_item_string_decref(dict, "uregs", 760 - _PyUnicode_FromString(bf)); 761 + if (sample->user_regs) { 762 + if (!bf) { 763 + bf = malloc(size); 764 + if (!bf) 765 + return -1; 766 + } 767 + regs_map(sample->user_regs, attr->sample_regs_user, arch, bf, size); 768 + 769 + pydict_set_item_string_decref(dict, "uregs", 770 + _PyUnicode_FromString(bf)); 771 + } 761 772 free(bf); 762 773 763 774 return 0;
+65 -29
tools/perf/util/session.c
··· 950 950 951 951 static void regs_user__printf(struct perf_sample *sample, const char *arch) 952 952 { 953 - struct regs_dump *user_regs = &sample->user_regs; 953 + struct regs_dump *user_regs; 954 + 955 + if (!sample->user_regs) 956 + return; 957 + 958 + user_regs = perf_sample__user_regs(sample); 954 959 955 960 if (user_regs->regs) 956 961 regs__printf("user", user_regs, arch); ··· 963 958 964 959 static void regs_intr__printf(struct perf_sample *sample, const char *arch) 965 960 { 966 - struct regs_dump *intr_regs = &sample->intr_regs; 961 + struct regs_dump *intr_regs; 962 + 963 + if (!sample->intr_regs) 964 + return; 965 + 966 + intr_regs = perf_sample__intr_regs(sample); 967 967 968 968 if (intr_regs->regs) 969 969 regs__printf("intr", intr_regs, arch); ··· 1361 1351 const char *file_path) 1362 1352 { 1363 1353 struct perf_sample sample; 1364 - int ret = evlist__parse_sample(session->evlist, event, &sample); 1354 + int ret; 1365 1355 1356 + perf_sample__init(&sample, /*all=*/false); 1357 + ret = evlist__parse_sample(session->evlist, event, &sample); 1366 1358 if (ret) { 1367 1359 pr_err("Can't parse sample, err = %d\n", ret); 1368 - return ret; 1360 + goto out; 1369 1361 } 1370 1362 1371 1363 ret = auxtrace__process_event(session, event, &sample, tool); 1372 1364 if (ret < 0) 1373 - return ret; 1374 - if (ret > 0) 1375 - return 0; 1365 + goto out; 1366 + if (ret > 0) { 1367 + ret = 0; 1368 + goto out; 1369 + } 1376 1370 1377 1371 ret = machines__deliver_event(&session->machines, session->evlist, 1378 1372 event, &sample, tool, file_offset, file_path); 1379 1373 1380 1374 if (dump_trace && sample.aux_sample.size) 1381 1375 auxtrace__dump_auxtrace_sample(session, &sample); 1382 - 1376 + out: 1377 + perf_sample__exit(&sample); 1383 1378 return ret; 1384 1379 } 1385 1380 ··· 1395 1380 { 1396 1381 struct ordered_events *oe = &session->ordered_events; 1397 1382 const struct perf_tool *tool = session->tool; 1398 - struct perf_sample sample = { .time = 0, }; 1383 + struct perf_sample sample; 1399 1384 int fd = perf_data__fd(session->data); 1400 1385 int err; 1401 1386 1387 + perf_sample__init(&sample, /*all=*/true); 1402 1388 if (event->header.type != PERF_RECORD_COMPRESSED || perf_tool__compressed_is_stub(tool)) 1403 1389 dump_event(session->evlist, event, file_offset, &sample, file_path); 1404 1390 ··· 1411 1395 perf_session__set_id_hdr_size(session); 1412 1396 perf_session__set_comm_exec(session); 1413 1397 } 1414 - return err; 1398 + break; 1415 1399 case PERF_RECORD_EVENT_UPDATE: 1416 - return tool->event_update(tool, event, &session->evlist); 1400 + err = tool->event_update(tool, event, &session->evlist); 1401 + break; 1417 1402 case PERF_RECORD_HEADER_EVENT_TYPE: 1418 1403 /* 1419 1404 * Deprecated, but we need to handle it for sake 1420 1405 * of old data files create in pipe mode. 1421 1406 */ 1422 - return 0; 1407 + err = 0; 1408 + break; 1423 1409 case PERF_RECORD_HEADER_TRACING_DATA: 1424 1410 /* 1425 1411 * Setup for reading amidst mmap, but only when we ··· 1430 1412 */ 1431 1413 if (!perf_data__is_pipe(session->data)) 1432 1414 lseek(fd, file_offset, SEEK_SET); 1433 - return tool->tracing_data(session, event); 1415 + err = tool->tracing_data(session, event); 1416 + break; 1434 1417 case PERF_RECORD_HEADER_BUILD_ID: 1435 - return tool->build_id(session, event); 1418 + err = tool->build_id(session, event); 1419 + break; 1436 1420 case PERF_RECORD_FINISHED_ROUND: 1437 - return tool->finished_round(tool, event, oe); 1421 + err = tool->finished_round(tool, event, oe); 1422 + break; 1438 1423 case PERF_RECORD_ID_INDEX: 1439 - return tool->id_index(session, event); 1424 + err = tool->id_index(session, event); 1425 + break; 1440 1426 case PERF_RECORD_AUXTRACE_INFO: 1441 - return tool->auxtrace_info(session, event); 1427 + err = tool->auxtrace_info(session, event); 1428 + break; 1442 1429 case PERF_RECORD_AUXTRACE: 1443 1430 /* 1444 1431 * Setup for reading amidst mmap, but only when we ··· 1452 1429 */ 1453 1430 if (!perf_data__is_pipe(session->data)) 1454 1431 lseek(fd, file_offset + event->header.size, SEEK_SET); 1455 - return tool->auxtrace(session, event); 1432 + err = tool->auxtrace(session, event); 1433 + break; 1456 1434 case PERF_RECORD_AUXTRACE_ERROR: 1457 1435 perf_session__auxtrace_error_inc(session, event); 1458 - return tool->auxtrace_error(session, event); 1436 + err = tool->auxtrace_error(session, event); 1437 + break; 1459 1438 case PERF_RECORD_THREAD_MAP: 1460 - return tool->thread_map(session, event); 1439 + err = tool->thread_map(session, event); 1440 + break; 1461 1441 case PERF_RECORD_CPU_MAP: 1462 - return tool->cpu_map(session, event); 1442 + err = tool->cpu_map(session, event); 1443 + break; 1463 1444 case PERF_RECORD_STAT_CONFIG: 1464 - return tool->stat_config(session, event); 1445 + err = tool->stat_config(session, event); 1446 + break; 1465 1447 case PERF_RECORD_STAT: 1466 - return tool->stat(session, event); 1448 + err = tool->stat(session, event); 1449 + break; 1467 1450 case PERF_RECORD_STAT_ROUND: 1468 - return tool->stat_round(session, event); 1451 + err = tool->stat_round(session, event); 1452 + break; 1469 1453 case PERF_RECORD_TIME_CONV: 1470 1454 session->time_conv = event->time_conv; 1471 - return tool->time_conv(session, event); 1455 + err = tool->time_conv(session, event); 1456 + break; 1472 1457 case PERF_RECORD_HEADER_FEATURE: 1473 - return tool->feature(session, event); 1458 + err = tool->feature(session, event); 1459 + break; 1474 1460 case PERF_RECORD_COMPRESSED: 1475 1461 err = tool->compressed(session, event, file_offset, file_path); 1476 1462 if (err) 1477 1463 dump_event(session->evlist, event, file_offset, &sample, file_path); 1478 - return err; 1464 + break; 1479 1465 case PERF_RECORD_FINISHED_INIT: 1480 - return tool->finished_init(session, event); 1466 + err = tool->finished_init(session, event); 1467 + break; 1481 1468 default: 1482 - return -EINVAL; 1469 + err = -EINVAL; 1470 + break; 1483 1471 } 1472 + perf_sample__exit(&sample); 1473 + return err; 1484 1474 } 1485 1475 1486 1476 int perf_session__deliver_synth_event(struct perf_session *session,
+12 -12
tools/perf/util/synthetic-events.c
··· 1508 1508 } 1509 1509 1510 1510 if (type & PERF_SAMPLE_REGS_USER) { 1511 - if (sample->user_regs.abi) { 1511 + if (sample->user_regs && sample->user_regs->abi) { 1512 1512 result += sizeof(u64); 1513 - sz = hweight64(sample->user_regs.mask) * sizeof(u64); 1513 + sz = hweight64(sample->user_regs->mask) * sizeof(u64); 1514 1514 result += sz; 1515 1515 } else { 1516 1516 result += sizeof(u64); ··· 1536 1536 result += sizeof(u64); 1537 1537 1538 1538 if (type & PERF_SAMPLE_REGS_INTR) { 1539 - if (sample->intr_regs.abi) { 1539 + if (sample->intr_regs && sample->intr_regs->abi) { 1540 1540 result += sizeof(u64); 1541 - sz = hweight64(sample->intr_regs.mask) * sizeof(u64); 1541 + sz = hweight64(sample->intr_regs->mask) * sizeof(u64); 1542 1542 result += sz; 1543 1543 } else { 1544 1544 result += sizeof(u64); ··· 1707 1707 } 1708 1708 1709 1709 if (type & PERF_SAMPLE_REGS_USER) { 1710 - if (sample->user_regs.abi) { 1711 - *array++ = sample->user_regs.abi; 1712 - sz = hweight64(sample->user_regs.mask) * sizeof(u64); 1713 - memcpy(array, sample->user_regs.regs, sz); 1710 + if (sample->user_regs && sample->user_regs->abi) { 1711 + *array++ = sample->user_regs->abi; 1712 + sz = hweight64(sample->user_regs->mask) * sizeof(u64); 1713 + memcpy(array, sample->user_regs->regs, sz); 1714 1714 array = (void *)array + sz; 1715 1715 } else { 1716 1716 *array++ = 0; ··· 1743 1743 } 1744 1744 1745 1745 if (type & PERF_SAMPLE_REGS_INTR) { 1746 - if (sample->intr_regs.abi) { 1747 - *array++ = sample->intr_regs.abi; 1748 - sz = hweight64(sample->intr_regs.mask) * sizeof(u64); 1749 - memcpy(array, sample->intr_regs.regs, sz); 1746 + if (sample->intr_regs && sample->intr_regs->abi) { 1747 + *array++ = sample->intr_regs->abi; 1748 + sz = hweight64(sample->intr_regs->mask) * sizeof(u64); 1749 + memcpy(array, sample->intr_regs->regs, sz); 1750 1750 array = (void *)array + sz; 1751 1751 } else { 1752 1752 *array++ = 0;
+6 -3
tools/perf/util/unwind-libdw.c
··· 190 190 int offset; 191 191 int ret; 192 192 193 - ret = perf_reg_value(&start, &ui->sample->user_regs, 193 + if (!ui->sample->user_regs) 194 + return false; 195 + 196 + ret = perf_reg_value(&start, ui->sample->user_regs, 194 197 perf_arch_reg_sp(arch)); 195 198 if (ret) 196 199 return false; ··· 276 273 Dwarf_Word ip; 277 274 int err = -EINVAL, i; 278 275 279 - if (!data->user_regs.regs) 276 + if (!data->user_regs || !data->user_regs->regs) 280 277 return -EINVAL; 281 278 282 279 ui = zalloc(sizeof(ui_buf) + sizeof(ui_buf.entries[0]) * max_stack); ··· 289 286 if (!ui->dwfl) 290 287 goto out; 291 288 292 - err = perf_reg_value(&ip, &data->user_regs, perf_arch_reg_ip(arch)); 289 + err = perf_reg_value(&ip, data->user_regs, perf_arch_reg_ip(arch)); 293 290 if (err) 294 291 goto out; 295 292