Re: [patch v9 02/23] linux, btrace: perf_event based branch tracing

Mark Kettenis
2013-03-06T10:11:47Z

> From: Markus Metzger <markus.t.metzger@intel.com>
> Date: Mon, 4 Mar 2013 18:05:49 +0100
>
> Implement branch tracing on Linux based on perf_event such taht it
> can be shared between gdb and gdbserver.
>
> The actual btrace target ops will be implemented on top.
>
> 2013-03-04 Markus Metzger <markus.t.metzger@intel.com>
>
> * common/linux_btrace.h: New file.
> * common/linux_btrace.c: New file.
> * Makefile.in (SFILES): Add btrace.c.
> (HFILES_NO_SRCDIR): Add common/linux-btrace.h.
> (COMMON_OBS): Add btrace.o.
> (linux-btrace.o): New rule.
>
> gdbserver/
> * Makefile.in (SFILES): Add $(srcdir)/common/linux-btrace.c.
> (linux_btrace_h): New variable.
> (linux-btrace.o): New rule.

> +/* See linux-btrace.h. */
> +
> +VEC (btrace_block_s) *
> +linux_read_btrace (struct btrace_target_info *tinfo)
> +{
> + VEC (btrace_block_s) *btrace = NULL;
> + volatile struct perf_event_mmap_page *header;
> + const uint8_t *begin, *end, *start;
> + unsigned long data_head, retries = 5;
> + size_t buffer_size;
> +
> + header = perf_event_header (tinfo);
> + buffer_size = perf_event_buffer_size (tinfo);
> +
> + /* We may need to retry reading the trace. See below. */
> + while (retries--)
> + {
> + data_head = header->data_head;
> +
> + /* Make sure the trace data is up-to-date. */
> + memory_barrier ();

The barrier here makes absolutely no sense to me. It's only a
compiler barrier and declaring header as volatile should be enough to
force the compiler to fetch HEADER->data_head from memory.

> +
> + /* If there's new trace, let's read it. */
> + if (data_head != tinfo->data_head)
> + {
> + /* Data_head keeps growing; the buffer itself is circular. */
> + begin = perf_event_buffer_begin (tinfo);
> + start = begin + data_head % buffer_size;
> +
> + if (data_head <= buffer_size)
> + end = start;
> + else
> + end = perf_event_buffer_end (tinfo);
> +
> + btrace = perf_event_read_bts (tinfo, begin, end, start);
> + }
> +
> + /* The stopping thread notifies its ptracer before it is scheduled out.
> + On multi-core systems, the debugger might therefore run while the
> + kernel might be writing the last branch trace records.
> +
> + Let's check whether the data head moved while we read the trace. */
> + if (data_head == header->data_head)
> + break;
> + }