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

powerpc/perf/vpa-dtl: Handle the writing of perf record when aux wake up is needed

Handle the case when the aux buffer is going to be full and
data needs to be written to the data file. perf_aux_output_begin()
function checks if there is enough space depending on the values of
aux_wakeup and aux_watermark which is part of "struct perf_buffer".
Inorder to maintain where to write to aux buffer, add two fields
to "struct vpa_pmu_buf". Field "threshold" to indicate total possible
DTL entries that can be contained in aux buffer and field "full" to
indicate anytime when buffer is full. In perf_aux_output_end, there
is check to see if wake up is needed based on aux head value.

In vpa_dtl_capture_aux(), check if there is enough space to contain the
DTL data. If not, save the data for available memory and set full to true.
Set head of private aux to zero when buffer is full so that next data
will be copied to beginning of the buffer. The address used for copying
to aux is "aux_copy_buf + buf->head". So once buffer is full, set head
to zero, so that next time it will be written from start of the buffer.

Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
Tested-by: Tejas Manhas <tejas05@linux.ibm.com>
Tested-by: Venkat Rao Bagalkote <venkat88@linux.ibm.com>
Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com>
Link: https://patch.msgid.link/20250915102947.26681-7-atrajeev@linux.ibm.com

authored by

Athira Rajeev and committed by
Madhavan Srinivasan
b5e71caf 2de8b6dd

+52 -2
+52 -2
arch/powerpc/perf/vpa-dtl.c
··· 85 85 u64 *base; 86 86 u64 size; 87 87 u64 head; 88 + u64 head_size; 88 89 /* boot timebase and frequency needs to be saved only at once */ 89 90 int boottb_freq_saved; 91 + u64 threshold; 92 + bool full; 90 93 }; 91 94 92 95 /* ··· 124 121 struct dtl_entry *aux_copy_buf = (struct dtl_entry *)buf->base; 125 122 126 123 /* 124 + * check if there is enough space to contain the 125 + * DTL data. If not, save the data for available 126 + * memory and set full to true. 127 + */ 128 + if (buf->head + *n_entries >= buf->threshold) { 129 + *n_entries = buf->threshold - buf->head; 130 + buf->full = 1; 131 + } 132 + 133 + /* 127 134 * Copy to AUX buffer from per-thread address 128 135 */ 129 136 memcpy(aux_copy_buf + buf->head, &dtl->buf[index], *n_entries * sizeof(struct dtl_entry)); 137 + 138 + if (buf->full) { 139 + /* 140 + * Set head of private aux to zero when buffer is full 141 + * so that next data will be copied to beginning of the 142 + * buffer 143 + */ 144 + buf->head = 0; 145 + return; 146 + } 130 147 131 148 buf->head += *n_entries; 132 149 ··· 201 178 struct vpa_pmu_buf *aux_buf; 202 179 203 180 struct vpa_dtl *dtl = &per_cpu(vpa_dtl_cpu, event->cpu); 181 + u64 size; 204 182 205 183 cur_idx = be64_to_cpu(lppaca_of(event->cpu).dtl_idx); 206 184 last_idx = dtl->last_idx; ··· 246 222 n_req -= read_size; 247 223 n_read += read_size; 248 224 i = 0; 225 + if (aux_buf->full) { 226 + size = (n_read * sizeof(struct dtl_entry)); 227 + if ((size + aux_buf->head_size) > aux_buf->size) { 228 + size = aux_buf->size - aux_buf->head_size; 229 + perf_aux_output_end(&vpa_ctx->handle, size); 230 + aux_buf->head = 0; 231 + aux_buf->head_size = 0; 232 + } else { 233 + aux_buf->head_size += (n_read * sizeof(struct dtl_entry)); 234 + perf_aux_output_end(&vpa_ctx->handle, n_read * sizeof(struct dtl_entry)); 235 + } 236 + goto out; 237 + } 249 238 } 250 239 251 240 /* .. and now the head */ 252 241 vpa_dtl_capture_aux(&n_req, aux_buf, dtl, i); 253 242 254 - /* Move the aux->head to indicate size of data in aux buffer */ 255 - perf_aux_output_end(&vpa_ctx->handle, (n_req + n_read) * sizeof(struct dtl_entry)); 243 + size = ((n_req + n_read) * sizeof(struct dtl_entry)); 244 + if ((size + aux_buf->head_size) > aux_buf->size) { 245 + size = aux_buf->size - aux_buf->head_size; 246 + perf_aux_output_end(&vpa_ctx->handle, size); 247 + aux_buf->head = 0; 248 + aux_buf->head_size = 0; 249 + } else { 250 + aux_buf->head_size += ((n_req + n_read) * sizeof(struct dtl_entry)); 251 + /* Move the aux->head to indicate size of data in aux buffer */ 252 + perf_aux_output_end(&vpa_ctx->handle, (n_req + n_read) * sizeof(struct dtl_entry)); 253 + } 254 + out: 255 + aux_buf->full = 0; 256 256 } 257 257 258 258 /* ··· 539 491 540 492 buf->size = nr_pages << PAGE_SHIFT; 541 493 buf->head = 0; 494 + buf->head_size = 0; 542 495 buf->boottb_freq_saved = 0; 496 + buf->threshold = ((buf->size - 32) / sizeof(struct dtl_entry)); 543 497 return no_free_ptr(buf); 544 498 } 545 499