Lines Matching +full:t +full:- +full:head
1 // SPDX-License-Identifier: GPL-2.0
3 * Performance events ring-buffer code:
6 * Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar
7 * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra
22 atomic_set(&handle->rb->poll, EPOLLIN); in perf_output_wakeup()
24 handle->event->pending_wakeup = 1; in perf_output_wakeup()
25 irq_work_queue(&handle->event->pending_irq); in perf_output_wakeup()
29 * We need to ensure a later event_id doesn't publish a head when a former
30 * event isn't done writing. However since we need to deal with NMIs we
33 * We only publish the head (and generate a wakeup) when the outer-most
38 struct perf_buffer *rb = handle->rb; in perf_output_get_handle()
46 (*(volatile unsigned int *)&rb->nest)++; in perf_output_get_handle()
47 handle->wakeup = local_read(&rb->wakeup); in perf_output_get_handle()
52 struct perf_buffer *rb = handle->rb; in perf_output_put_handle()
53 unsigned long head; in perf_output_put_handle() local
57 * If this isn't the outermost nesting, we don't have to update in perf_output_put_handle()
58 * @rb->user_page->data_head. in perf_output_put_handle()
60 nest = READ_ONCE(rb->nest); in perf_output_put_handle()
62 WRITE_ONCE(rb->nest, nest - 1); in perf_output_put_handle()
68 * In order to avoid publishing a head value that goes backwards, in perf_output_put_handle()
69 * we must ensure the load of @rb->head happens after we've in perf_output_put_handle()
70 * incremented @rb->nest. in perf_output_put_handle()
72 * Otherwise we can observe a @rb->head value before one published in perf_output_put_handle()
76 head = local_read(&rb->head); in perf_output_put_handle()
79 * IRQ/NMI can happen here and advance @rb->head, causing our in perf_output_put_handle()
88 * if (LOAD ->data_tail) { LOAD ->data_head in perf_output_put_handle()
92 * STORE ->data_head STORE ->data_tail in perf_output_put_handle()
98 * the ->data_tail and the stores of $data. In case ->data_tail in perf_output_put_handle()
110 WRITE_ONCE(rb->user_page->data_head, head); in perf_output_put_handle()
113 * We must publish the head before decrementing the nest count, in perf_output_put_handle()
114 * otherwise an IRQ/NMI can publish a more recent head value and our in perf_output_put_handle()
118 WRITE_ONCE(rb->nest, 0); in perf_output_put_handle()
121 * Ensure we decrement @rb->nest before we validate the @rb->head. in perf_output_put_handle()
125 if (unlikely(head != local_read(&rb->head))) { in perf_output_put_handle()
126 WRITE_ONCE(rb->nest, 1); in perf_output_put_handle()
130 if (handle->wakeup != local_read(&rb->wakeup)) in perf_output_put_handle()
138 ring_buffer_has_space(unsigned long head, unsigned long tail, in ring_buffer_has_space() argument
143 return CIRC_SPACE(head, tail, data_size) >= size; in ring_buffer_has_space()
145 return CIRC_SPACE(tail, head, data_size) >= size; in ring_buffer_has_space()
155 unsigned long tail, offset, head; in __perf_output_begin() local
167 if (event->parent) in __perf_output_begin()
168 event = event->parent; in __perf_output_begin()
170 rb = rcu_dereference(event->rb); in __perf_output_begin()
174 if (unlikely(rb->paused)) { in __perf_output_begin()
175 if (rb->nr_pages) { in __perf_output_begin()
176 local_inc(&rb->lost); in __perf_output_begin()
177 atomic64_inc(&event->lost_samples); in __perf_output_begin()
182 handle->rb = rb; in __perf_output_begin()
183 handle->event = event; in __perf_output_begin()
185 have_lost = local_read(&rb->lost); in __perf_output_begin()
188 if (event->attr.sample_id_all) in __perf_output_begin()
189 size += event->id_header_size; in __perf_output_begin()
194 offset = local_read(&rb->head); in __perf_output_begin()
196 head = offset; in __perf_output_begin()
197 tail = READ_ONCE(rb->user_page->data_tail); in __perf_output_begin()
198 if (!rb->overwrite) { in __perf_output_begin()
199 if (unlikely(!ring_buffer_has_space(head, tail, in __perf_output_begin()
218 head += size; in __perf_output_begin()
220 head -= size; in __perf_output_begin()
221 } while (!local_try_cmpxchg(&rb->head, &offset, head)); in __perf_output_begin()
224 offset = head; in __perf_output_begin()
225 head = (u64)(-head); in __perf_output_begin()
233 if (unlikely(head - local_read(&rb->wakeup) > rb->watermark)) in __perf_output_begin()
234 local_add(rb->watermark, &rb->wakeup); in __perf_output_begin()
238 handle->page = (offset >> page_shift) & (rb->nr_pages - 1); in __perf_output_begin()
239 offset &= (1UL << page_shift) - 1; in __perf_output_begin()
240 handle->addr = rb->data_pages[handle->page] + offset; in __perf_output_begin()
241 handle->size = (1UL << page_shift) - offset; in __perf_output_begin()
247 lost_event.id = event->id; in __perf_output_begin()
248 lost_event.lost = local_xchg(&rb->lost, 0); in __perf_output_begin()
259 local_inc(&rb->lost); in __perf_output_begin()
260 atomic64_inc(&event->lost_samples); in __perf_output_begin()
265 return -ENOSPC; in __perf_output_begin()
315 rb->watermark = min(max_size, watermark); in ring_buffer_init()
317 if (!rb->watermark) in ring_buffer_init()
318 rb->watermark = max_size / 2; in ring_buffer_init()
321 rb->overwrite = 0; in ring_buffer_init()
323 rb->overwrite = 1; in ring_buffer_init()
325 refcount_set(&rb->refcount, 1); in ring_buffer_init()
327 INIT_LIST_HEAD(&rb->event_list); in ring_buffer_init()
328 spin_lock_init(&rb->event_lock); in ring_buffer_init()
331 * perf_output_begin() only checks rb->paused, therefore in ring_buffer_init()
332 * rb->paused must be true if we have no pages for output. in ring_buffer_init()
334 if (!rb->nr_pages) in ring_buffer_init()
335 rb->paused = 1; in ring_buffer_init()
341 * OVERWRITE is determined by perf_aux_output_end() and can't in perf_aux_output_flag()
347 handle->aux_flags |= flags; in perf_aux_output_flag()
373 if (output_event->parent) in perf_aux_output_begin()
374 output_event = output_event->parent; in perf_aux_output_begin()
379 * to make sure it doesn't disappear under us. in perf_aux_output_begin()
396 if (!atomic_read(&rb->aux_mmap_count)) in perf_aux_output_begin()
399 if (!refcount_inc_not_zero(&rb->aux_refcount)) in perf_aux_output_begin()
402 nest = READ_ONCE(rb->aux_nest); in perf_aux_output_begin()
410 WRITE_ONCE(rb->aux_nest, nest + 1); in perf_aux_output_begin()
412 aux_head = rb->aux_head; in perf_aux_output_begin()
414 handle->rb = rb; in perf_aux_output_begin()
415 handle->event = event; in perf_aux_output_begin()
416 handle->head = aux_head; in perf_aux_output_begin()
417 handle->size = 0; in perf_aux_output_begin()
418 handle->aux_flags = 0; in perf_aux_output_begin()
423 * (B) <-> (C) ordering is still observed by the pmu driver. in perf_aux_output_begin()
425 if (!rb->aux_overwrite) { in perf_aux_output_begin()
426 aux_tail = READ_ONCE(rb->user_page->aux_tail); in perf_aux_output_begin()
427 handle->wakeup = rb->aux_wakeup + rb->aux_watermark; in perf_aux_output_begin()
428 if (aux_head - aux_tail < perf_aux_size(rb)) in perf_aux_output_begin()
429 handle->size = CIRC_SPACE(aux_head, aux_tail, perf_aux_size(rb)); in perf_aux_output_begin()
432 * handle->size computation depends on aux_tail load; this forms a in perf_aux_output_begin()
436 if (!handle->size) { /* A, matches D */ in perf_aux_output_begin()
437 event->pending_disable = smp_processor_id(); in perf_aux_output_begin()
439 WRITE_ONCE(rb->aux_nest, 0); in perf_aux_output_begin()
444 return handle->rb->aux_priv; in perf_aux_output_begin()
447 /* can't be last */ in perf_aux_output_begin()
452 handle->event = NULL; in perf_aux_output_begin()
460 if (rb->aux_overwrite) in rb_need_aux_wakeup()
463 if (rb->aux_head - rb->aux_wakeup >= rb->aux_watermark) { in rb_need_aux_wakeup()
464 rb->aux_wakeup = rounddown(rb->aux_head, rb->aux_watermark); in rb_need_aux_wakeup()
483 bool wakeup = !!(handle->aux_flags & PERF_AUX_FLAG_TRUNCATED); in perf_aux_output_end()
484 struct perf_buffer *rb = handle->rb; in perf_aux_output_end()
488 if (rb->aux_overwrite) { in perf_aux_output_end()
489 handle->aux_flags |= PERF_AUX_FLAG_OVERWRITE; in perf_aux_output_end()
491 aux_head = handle->head; in perf_aux_output_end()
492 rb->aux_head = aux_head; in perf_aux_output_end()
494 handle->aux_flags &= ~PERF_AUX_FLAG_OVERWRITE; in perf_aux_output_end()
496 aux_head = rb->aux_head; in perf_aux_output_end()
497 rb->aux_head += size; in perf_aux_output_end()
504 * useful, as they don't communicate any *new* information, in perf_aux_output_end()
505 * aside from the short-lived offset, that becomes history at in perf_aux_output_end()
506 * the next event sched-in and therefore isn't useful. in perf_aux_output_end()
509 * offset. So, from now on we don't output AUX records that in perf_aux_output_end()
512 if (size || (handle->aux_flags & ~(u64)PERF_AUX_FLAG_OVERWRITE)) in perf_aux_output_end()
513 perf_event_aux_event(handle->event, aux_head, size, in perf_aux_output_end()
514 handle->aux_flags); in perf_aux_output_end()
516 WRITE_ONCE(rb->user_page->aux_head, rb->aux_head); in perf_aux_output_end()
521 if (handle->aux_flags & PERF_AUX_FLAG_TRUNCATED) in perf_aux_output_end()
522 handle->event->pending_disable = smp_processor_id(); in perf_aux_output_end()
526 handle->event = NULL; in perf_aux_output_end()
528 WRITE_ONCE(rb->aux_nest, 0); in perf_aux_output_end()
529 /* can't be last */ in perf_aux_output_end()
541 struct perf_buffer *rb = handle->rb; in perf_aux_output_skip()
543 if (size > handle->size) in perf_aux_output_skip()
544 return -ENOSPC; in perf_aux_output_skip()
546 rb->aux_head += size; in perf_aux_output_skip()
548 WRITE_ONCE(rb->user_page->aux_head, rb->aux_head); in perf_aux_output_skip()
551 handle->wakeup = rb->aux_wakeup + rb->aux_watermark; in perf_aux_output_skip()
554 handle->head = rb->aux_head; in perf_aux_output_skip()
555 handle->size -= size; in perf_aux_output_skip()
564 if (!handle->event) in perf_get_aux()
567 return handle->rb->aux_priv; in perf_get_aux()
578 struct perf_buffer *rb = aux_handle->rb; in perf_output_copy_aux()
582 from &= (rb->aux_nr_pages << PAGE_SHIFT) - 1; in perf_output_copy_aux()
583 to &= (rb->aux_nr_pages << PAGE_SHIFT) - 1; in perf_output_copy_aux()
586 tocopy = PAGE_SIZE - offset_in_page(from); in perf_output_copy_aux()
588 tocopy = min(tocopy, to - from); in perf_output_copy_aux()
592 addr = rb->aux_pages[from >> PAGE_SHIFT]; in perf_output_copy_aux()
597 return -EFAULT; in perf_output_copy_aux()
601 from &= (rb->aux_nr_pages << PAGE_SHIFT) - 1; in perf_output_copy_aux()
618 } while (!page && order--); in rb_alloc_aux_page()
623 * if we managed to secure a high-order allocation, in rb_alloc_aux_page()
637 struct page *page = virt_to_page(rb->aux_pages[idx]); in rb_free_aux_page()
640 page->mapping = NULL; in rb_free_aux_page()
656 if (rb->aux_priv) { in __rb_free_aux()
657 rb->free_aux(rb->aux_priv); in __rb_free_aux()
658 rb->free_aux = NULL; in __rb_free_aux()
659 rb->aux_priv = NULL; in __rb_free_aux()
662 if (rb->aux_nr_pages) { in __rb_free_aux()
663 for (pg = 0; pg < rb->aux_nr_pages; pg++) in __rb_free_aux()
666 kfree(rb->aux_pages); in __rb_free_aux()
667 rb->aux_nr_pages = 0; in __rb_free_aux()
675 int node = (event->cpu == -1) ? -1 : cpu_to_node(event->cpu); in rb_alloc_aux()
676 int ret = -ENOMEM, max_order; in rb_alloc_aux()
679 return -EOPNOTSUPP; in rb_alloc_aux()
687 watermark = nr_pages << (PAGE_SHIFT - 1); in rb_alloc_aux()
708 return -ENOMEM; in rb_alloc_aux()
709 rb->aux_pages = kcalloc_node(nr_pages, sizeof(void *), GFP_KERNEL, in rb_alloc_aux()
711 if (!rb->aux_pages) in rb_alloc_aux()
712 return -ENOMEM; in rb_alloc_aux()
714 rb->free_aux = event->pmu->free_aux; in rb_alloc_aux()
715 for (rb->aux_nr_pages = 0; rb->aux_nr_pages < nr_pages;) { in rb_alloc_aux()
719 order = min(max_order, ilog2(nr_pages - rb->aux_nr_pages)); in rb_alloc_aux()
724 for (last = rb->aux_nr_pages + (1 << page_private(page)); in rb_alloc_aux()
725 last > rb->aux_nr_pages; rb->aux_nr_pages++) in rb_alloc_aux()
726 rb->aux_pages[rb->aux_nr_pages] = page_address(page++); in rb_alloc_aux()
730 * In overwrite mode, PMUs that don't support SG may not handle more in rb_alloc_aux()
735 if ((event->pmu->capabilities & PERF_PMU_CAP_AUX_NO_SG) && in rb_alloc_aux()
737 struct page *page = virt_to_page(rb->aux_pages[0]); in rb_alloc_aux()
743 rb->aux_priv = event->pmu->setup_aux(event, rb->aux_pages, nr_pages, in rb_alloc_aux()
745 if (!rb->aux_priv) in rb_alloc_aux()
756 refcount_set(&rb->aux_refcount, 1); in rb_alloc_aux()
758 rb->aux_overwrite = overwrite; in rb_alloc_aux()
759 rb->aux_watermark = watermark; in rb_alloc_aux()
763 rb->aux_pgoff = pgoff; in rb_alloc_aux()
772 if (refcount_dec_and_test(&rb->aux_refcount)) in rb_free_aux()
779 * Back perf_mmap() with regular GFP_KERNEL-0 pages.
785 if (pgoff > rb->nr_pages) in __perf_mmap_to_page()
789 return virt_to_page(rb->user_page); in __perf_mmap_to_page()
791 return virt_to_page(rb->data_pages[pgoff - 1]); in __perf_mmap_to_page()
799 node = (cpu == -1) ? cpu : cpu_to_node(cpu); in perf_mmap_alloc_page()
811 page->mapping = NULL; in perf_mmap_free_page()
827 node = (cpu == -1) ? cpu : cpu_to_node(cpu); in rb_alloc()
832 rb->user_page = perf_mmap_alloc_page(cpu); in rb_alloc()
833 if (!rb->user_page) in rb_alloc()
837 rb->data_pages[i] = perf_mmap_alloc_page(cpu); in rb_alloc()
838 if (!rb->data_pages[i]) in rb_alloc()
842 rb->nr_pages = nr_pages; in rb_alloc()
849 for (i--; i >= 0; i--) in rb_alloc()
850 perf_mmap_free_page(rb->data_pages[i]); in rb_alloc()
852 perf_mmap_free_page(rb->user_page); in rb_alloc()
865 perf_mmap_free_page(rb->user_page); in rb_free()
866 for (i = 0; i < rb->nr_pages; i++) in rb_free()
867 perf_mmap_free_page(rb->data_pages[i]); in rb_free()
879 return vmalloc_to_page((void *)rb->user_page + pgoff * PAGE_SIZE); in __perf_mmap_to_page()
886 page->mapping = NULL; in perf_mmap_unmark_page()
898 base = rb->user_page; in rb_free_work()
909 schedule_work(&rb->work); in rb_free()
922 node = (cpu == -1) ? cpu : cpu_to_node(cpu); in rb_alloc()
927 INIT_WORK(&rb->work, rb_free_work); in rb_alloc()
933 rb->user_page = all_buf; in rb_alloc()
934 rb->data_pages[0] = all_buf + PAGE_SIZE; in rb_alloc()
936 rb->nr_pages = 1; in rb_alloc()
937 rb->page_order = ilog2(nr_pages); in rb_alloc()
956 if (rb->aux_nr_pages) { in perf_mmap_to_page()
958 if (pgoff > rb->aux_pgoff + rb->aux_nr_pages) in perf_mmap_to_page()
962 if (pgoff >= rb->aux_pgoff) { in perf_mmap_to_page()
963 int aux_pgoff = array_index_nospec(pgoff - rb->aux_pgoff, rb->aux_nr_pages); in perf_mmap_to_page()
964 return virt_to_page(rb->aux_pages[aux_pgoff]); in perf_mmap_to_page()