From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 10355 invoked by alias); 14 Jul 2014 13:57:03 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 10274 invoked by uid 89); 14 Jul 2014 13:57:03 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.8 required=5.0 tests=AWL,BAYES_00,RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mga09.intel.com Received: from mga09.intel.com (HELO mga09.intel.com) (134.134.136.24) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 14 Jul 2014 13:56:58 +0000 Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga102.jf.intel.com with ESMTP; 14 Jul 2014 06:51:20 -0700 X-ExtLoop1: 1 Received: from irvmail001.ir.intel.com ([163.33.26.43]) by orsmga001.jf.intel.com with ESMTP; 14 Jul 2014 06:56:38 -0700 Received: from ulvlx001.iul.intel.com (ulvlx001.iul.intel.com [172.28.207.17]) by irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id s6EDubO3009221; Mon, 14 Jul 2014 14:56:37 +0100 Received: from ulvlx001.iul.intel.com (localhost [127.0.0.1]) by ulvlx001.iul.intel.com with ESMTP id s6EDubat002099; Mon, 14 Jul 2014 15:56:37 +0200 Received: (from mmetzger@localhost) by ulvlx001.iul.intel.com with œ id s6EDubIi002095; Mon, 14 Jul 2014 15:56:37 +0200 From: Markus Metzger To: palves@redhat.com Cc: gdb-patches@sourceware.org Subject: [PATCH 03/12] btrace, linux: add perf event buffer abstraction Date: Mon, 14 Jul 2014 13:57:00 -0000 Message-Id: <1405346196-1804-4-git-send-email-markus.t.metzger@intel.com> In-Reply-To: <1405346196-1804-1-git-send-email-markus.t.metzger@intel.com> References: <1405346196-1804-1-git-send-email-markus.t.metzger@intel.com> X-IsSubscribed: yes X-SW-Source: 2014-07/txt/msg00330.txt.bz2 Collect perf event buffer related fields from btrace_target_info into a new struct perf_event_buffer. Update functions that operated on the buffer to take a struct perf_event_buffer pointer rather than a btrace_target_info pointer. We will need other perf event buffers with different content. 2014-07-14 Markus Metzger * common/linux-btrace.h (perf_event_buffer): New. (btrace_target_info) : Replace with ... : ... this. * common/linux-btrace.c (perf_event_header, perf_event_mmap_size) (perf_event_buffer_size, perf_event_buffer_begin) (perf_event_buffer_end): Update parameters. Updated users. (perf_event_map_buffer, perf_event_unmap_buffer) (perf_event_new_data): New. (linux_enable_btrace): Call perf_event_map_buffer. (linux_disable_btrace): Call perf_event_unmap_buffer. (linux_btrace_has_changed): Remove. --- gdb/nat/linux-btrace.c | 117 ++++++++++++++++++++++++++++++------------------- gdb/nat/linux-btrace.h | 29 ++++++++---- 2 files changed, 93 insertions(+), 53 deletions(-) diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c index 20b4ef0..f33a455 100644 --- a/gdb/nat/linux-btrace.c +++ b/gdb/nat/linux-btrace.c @@ -72,42 +72,90 @@ struct perf_event_sample /* Get the perf_event header. */ static inline volatile struct perf_event_mmap_page * -perf_event_header (struct btrace_target_info* tinfo) +perf_event_header (const struct perf_event_buffer *pevent) { - return tinfo->buffer; + return pevent->mem; } /* Get the size of the perf_event mmap buffer. */ static inline size_t -perf_event_mmap_size (const struct btrace_target_info *tinfo) +perf_event_mmap_size (const struct perf_event_buffer *pevent) { /* The branch trace buffer is preceded by a configuration page. */ - return (tinfo->size + 1) * PAGE_SIZE; + return (pevent->size + 1) * PAGE_SIZE; } /* Get the size of the perf_event buffer. */ static inline size_t -perf_event_buffer_size (struct btrace_target_info* tinfo) +perf_event_buffer_size (const struct perf_event_buffer *pevent) { - return tinfo->size * PAGE_SIZE; + return pevent->size * PAGE_SIZE; } /* Get the start address of the perf_event buffer. */ static inline const uint8_t * -perf_event_buffer_begin (struct btrace_target_info* tinfo) +perf_event_buffer_begin (const struct perf_event_buffer *pevent) { - return ((const uint8_t *) tinfo->buffer) + PAGE_SIZE; + return ((const uint8_t *) pevent->mem) + PAGE_SIZE; } /* Get the end address of the perf_event buffer. */ static inline const uint8_t * -perf_event_buffer_end (struct btrace_target_info* tinfo) +perf_event_buffer_end (const struct perf_event_buffer *pevent) { - return perf_event_buffer_begin (tinfo) + perf_event_buffer_size (tinfo); + return perf_event_buffer_begin (pevent) + perf_event_buffer_size (pevent); +} + +/* Map a perf event buffer. + Return zero on success; a negative number otherwise. */ + +static int +perf_event_map_buffer (struct perf_event_buffer *pev, int file, off_t offset) +{ + int pg; + + /* We try to allocate as much buffer as we can get. + We could allow the user to specify the size of the buffer, but then + we'd leave this search for the maximum buffer size to him. */ + for (pg = 4; pg >= 0; --pg) + { + /* The number of pages we request needs to be a power of two. */ + pev->size = 1 << pg; + pev->mem = mmap (NULL, perf_event_mmap_size (pev), + PROT_READ, MAP_SHARED, file, offset); + if (pev->mem != MAP_FAILED) + return 0; + } + + return -1; +} + +/* Unmap a perf event buffer. + Return zero on success; a negative number otherwise. */ + +static int +perf_event_unmap_buffer (struct perf_event_buffer *pev) +{ + int errcode; + + errcode = munmap (pev->mem, perf_event_mmap_size (pev)); + if (errcode != 0) + return errno; + + return 0; +} + +/* Return non-zero if there is new data in PEVENT; zero otherwise. */ + +static int +perf_event_new_data (const struct perf_event_buffer *pev) +{ + volatile struct perf_event_mmap_page *header = perf_event_header (pev); + return header->data_head != pev->data_head; } /* Check whether an address is in the kernel. */ @@ -447,7 +495,7 @@ struct btrace_target_info * linux_enable_btrace (ptid_t ptid) { struct btrace_target_info *tinfo; - int pid, pg; + int pid, errcode; tinfo = xzalloc (sizeof (*tinfo)); tinfo->ptid = ptid; @@ -475,20 +523,9 @@ linux_enable_btrace (ptid_t ptid) if (tinfo->file < 0) goto err; - /* We try to allocate as much buffer as we can get. - We could allow the user to specify the size of the buffer, but then - we'd leave this search for the maximum buffer size to him. */ - for (pg = 4; pg >= 0; --pg) - { - /* The number of pages we request needs to be a power of two. */ - tinfo->size = 1 << pg; - tinfo->buffer = mmap (NULL, perf_event_mmap_size (tinfo), - PROT_READ, MAP_SHARED, tinfo->file, 0); - if (tinfo->buffer == MAP_FAILED) - continue; - - return tinfo; - } + errcode = perf_event_map_buffer (&tinfo->bts, tinfo->file, 0); + if (errcode == 0) + return tinfo; /* We were not able to allocate any buffer. */ close (tinfo->file); @@ -505,8 +542,7 @@ linux_disable_btrace (struct btrace_target_info *tinfo) { int errcode; - errno = 0; - errcode = munmap (tinfo->buffer, perf_event_mmap_size (tinfo)); + errcode = perf_event_unmap_buffer (&tinfo->bts); if (errcode != 0) return BTRACE_ERR_UNKNOWN; @@ -516,16 +552,6 @@ linux_disable_btrace (struct btrace_target_info *tinfo) return BTRACE_ERR_NONE; } -/* Check whether the branch trace has changed. */ - -static int -linux_btrace_has_changed (struct btrace_target_info *tinfo) -{ - volatile struct perf_event_mmap_page *header = perf_event_header (tinfo); - - return header->data_head != tinfo->data_head; -} - /* Read branch trace data in BTS format for the thread given by TINFO into BTRACE using the TYPE reading method. */ @@ -535,18 +561,21 @@ linux_read_bts (struct btrace_data_bts *btrace, enum btrace_read_type type) { volatile struct perf_event_mmap_page *header; + struct perf_event_buffer *pevent; const uint8_t *begin, *end, *start; unsigned long data_head, data_tail, retries = 5; size_t buffer_size, size; + pevent = &tinfo->bts; + /* For delta reads, we return at least the partial last block containing the current PC. */ - if (type == BTRACE_READ_NEW && !linux_btrace_has_changed (tinfo)) + if (type == BTRACE_READ_NEW && !perf_event_new_data (pevent)) return BTRACE_ERR_NONE; - header = perf_event_header (tinfo); - buffer_size = perf_event_buffer_size (tinfo); - data_tail = tinfo->data_head; + header = perf_event_header (pevent); + buffer_size = perf_event_buffer_size (pevent); + data_tail = pevent->data_head; /* We may need to retry reading the trace. See below. */ while (retries--) @@ -583,13 +612,13 @@ linux_read_bts (struct btrace_data_bts *btrace, } /* Data_head keeps growing; the buffer itself is circular. */ - begin = perf_event_buffer_begin (tinfo); + begin = perf_event_buffer_begin (pevent); start = begin + data_head % buffer_size; if (data_head <= buffer_size) end = start; else - end = perf_event_buffer_end (tinfo); + end = perf_event_buffer_end (pevent); btrace->blocks = perf_event_read_bts (tinfo, begin, end, start, size); @@ -602,7 +631,7 @@ linux_read_bts (struct btrace_data_bts *btrace, break; } - tinfo->data_head = data_head; + pevent->data_head = data_head; /* Prune the incomplete last block (i.e. the first one of inferior execution) if we're not doing a delta read. There is no way of filling in its zeroed diff --git a/gdb/nat/linux-btrace.h b/gdb/nat/linux-btrace.h index 7b02db5..5af3f87 100644 --- a/gdb/nat/linux-btrace.h +++ b/gdb/nat/linux-btrace.h @@ -33,6 +33,22 @@ # include #endif +#if HAVE_LINUX_PERF_EVENT_H +/* A Linux perf event buffer. */ +struct perf_event_buffer +{ + /* The mapped memory. */ + void *mem; + + /* The size of the mapped memory in pages excluding the initial + configuration page. */ + size_t size; + + /* The data_head value from the last read. */ + unsigned long data_head; +}; +#endif /* HAVE_LINUX_PERF_EVENT_H */ + /* Branch trace target information per thread. */ struct btrace_target_info { @@ -43,16 +59,11 @@ struct btrace_target_info /* The ptid of this thread. */ ptid_t ptid; - /* The mmap configuration mapping the branch trace perf_event buffer. - - file .. the file descriptor - buffer .. the mmapped memory buffer - size .. the buffer's size in pages without the configuration page - data_head .. the data head from the last read */ + /* The perf event file. */ int file; - void *buffer; - size_t size; - unsigned long data_head; + + /* The BTS perf event buffer. */ + struct perf_event_buffer bts; #endif /* HAVE_LINUX_PERF_EVENT_H */ /* The size of a pointer in bits for this thread. -- 1.8.3.1