From patchwork Mon Mar 6 16:00:18 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Arnez X-Patchwork-Id: 19434 Received: (qmail 96614 invoked by alias); 6 Mar 2017 16:01:58 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 96604 invoked by uid 89); 6 Mar 2017 16:01:57 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-24.1 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 spammy=fulfill, Round X-HELO: mx0a-001b2d01.pphosted.com Received: from mx0b-001b2d01.pphosted.com (HELO mx0a-001b2d01.pphosted.com) (148.163.158.5) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 06 Mar 2017 16:01:55 +0000 Received: from pps.filterd (m0098414.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.20/8.16.0.20) with SMTP id v26FrsYS061252 for ; Mon, 6 Mar 2017 11:01:54 -0500 Received: from e06smtp05.uk.ibm.com (e06smtp05.uk.ibm.com [195.75.94.101]) by mx0b-001b2d01.pphosted.com with ESMTP id 290c4uyay2-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Mon, 06 Mar 2017 11:01:54 -0500 Received: from localhost by e06smtp05.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 6 Mar 2017 16:01:52 -0000 Received: from d06dlp01.portsmouth.uk.ibm.com (9.149.20.13) by e06smtp05.uk.ibm.com (192.168.101.135) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Mon, 6 Mar 2017 16:01:43 -0000 Received: from b06cxnps4076.portsmouth.uk.ibm.com (d06relay13.portsmouth.uk.ibm.com [9.149.109.198]) by d06dlp01.portsmouth.uk.ibm.com (Postfix) with ESMTP id 93F1E17D805F for ; Mon, 6 Mar 2017 16:04:58 +0000 (GMT) Received: from d06av24.portsmouth.uk.ibm.com (d06av24.portsmouth.uk.ibm.com [9.149.105.60]) by b06cxnps4076.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id v26G1g5R46334106 for ; Mon, 6 Mar 2017 16:01:42 GMT Received: from d06av24.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 73A7D42056 for ; Mon, 6 Mar 2017 16:01:36 +0000 (GMT) Received: from d06av24.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 57D724204F for ; Mon, 6 Mar 2017 16:01:36 +0000 (GMT) Received: from oc1027705133.ibm.com (unknown [9.152.212.222]) by d06av24.portsmouth.uk.ibm.com (Postfix) with ESMTP for ; Mon, 6 Mar 2017 16:01:36 +0000 (GMT) From: Andreas Arnez To: gdb-patches@sourceware.org Subject: [PATCH 1/3] inf-ptrace: Do not stop memory transfers after a single word Date: Mon, 6 Mar 2017 17:00:18 +0100 In-Reply-To: <1488816060-20776-1-git-send-email-arnez@linux.vnet.ibm.com> References: <1488816060-20776-1-git-send-email-arnez@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 X-Content-Scanned: Fidelis XPS MAILER x-cbid: 17030616-0020-0000-0000-00000281B3BA X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 17030616-0021-0000-0000-00001F9E41F5 Message-Id: <1488816060-20776-2-git-send-email-arnez@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-03-06_12:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=1 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1702020001 definitions=main-1703060134 X-IsSubscribed: yes When inf_ptrace_xfer_partial performs a memory transfer via ptrace with PT_READ_I, PT_WRITE_I (aka PTRACE_PEEKTEXT, PTRACE_POKETEXT), etc., then it currently transfers at most one word. This behavior yields degraded performance, particularly if the caller has significant preparation work for each invocation. And indeed it has for writing, in memory_xfer_partial in target.c, where all of the remaining data to be transferred is copied to a temporary buffer each time, for breakpoint shadow handling. Thus large writes have quadratic runtime and can take hours. Note: On GNU/Linux targets GDB usually does not use inf_ptrace_xfer_partial for large memory *reads* from the inferior, but attempts a single read from /proc//mem instead. However, this is not currently true for memory *writes*. So the problem occurs on GNU/Linux when transferring large amounts of data *into* the inferior. This patch fixes the performance issue by attempting to fulfill the whole transfer request in inf_ptrace_xfer_partial, using a loop around the ptrace call. gdb/ChangeLog: PR gdb/21220 * inf-ptrace.c (inf_ptrace_xfer_partial): For memory transfers, loop over ptrace peek/poke until end of buffer or error. --- gdb/inf-ptrace.c | 115 ++++++++++++++++++++++++------------------------------- 1 file changed, 51 insertions(+), 64 deletions(-) diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c index 21578742..2989259 100644 --- a/gdb/inf-ptrace.c +++ b/gdb/inf-ptrace.c @@ -492,77 +492,64 @@ inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object, } #endif { - union - { - PTRACE_TYPE_RET word; - gdb_byte byte[sizeof (PTRACE_TYPE_RET)]; - } buffer; - ULONGEST rounded_offset; - ULONGEST partial_len; - - /* Round the start offset down to the next long word - boundary. */ - rounded_offset = offset & -(ULONGEST) sizeof (PTRACE_TYPE_RET); - - /* Since ptrace will transfer a single word starting at that - rounded_offset the partial_len needs to be adjusted down to - that (remember this function only does a single transfer). - Should the required length be even less, adjust it down - again. */ - partial_len = (rounded_offset + sizeof (PTRACE_TYPE_RET)) - offset; - if (partial_len > len) - partial_len = len; - - if (writebuf) + ULONGEST n; + unsigned chunk; + + /* We transfer aligned words. Thus align OFFSET down to a word + boundary and determine how many bytes to skip at the + beginning. */ + unsigned skip = offset & (sizeof (PTRACE_TYPE_RET) - 1); + offset -= skip; + + for (n = 0; + n < len; + n += chunk, offset += sizeof (PTRACE_TYPE_RET), skip = 0) { - /* If OFFSET:PARTIAL_LEN is smaller than - ROUNDED_OFFSET:WORDSIZE then a read/modify write will - be needed. Read in the entire word. */ - if (rounded_offset < offset - || (offset + partial_len - < rounded_offset + sizeof (PTRACE_TYPE_RET))) - /* Need part of initial word -- fetch it. */ - buffer.word = ptrace (PT_READ_I, pid, - (PTRACE_TYPE_ARG3)(uintptr_t) - rounded_offset, 0); - - /* Copy data to be written over corresponding part of - buffer. */ - memcpy (buffer.byte + (offset - rounded_offset), - writebuf, partial_len); - - errno = 0; - ptrace (PT_WRITE_D, pid, - (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset, - buffer.word); - if (errno) + /* Restrict to a chunk that fits in the current word. */ + chunk = std::min (sizeof (PTRACE_TYPE_RET) - skip, len - n); + + /* Use a union for type punning. */ + union + { + PTRACE_TYPE_RET word; + gdb_byte byte[sizeof (PTRACE_TYPE_RET)]; + } buf; + + /* Read the word, also when doing a partial word write. */ + if (readbuf || chunk < sizeof (PTRACE_TYPE_RET)) { - /* Using the appropriate one (I or D) is necessary for - Gould NP1, at least. */ errno = 0; - ptrace (PT_WRITE_I, pid, - (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset, - buffer.word); + buf.word = ptrace (PT_READ_I, pid, + (PTRACE_TYPE_ARG3)(uintptr_t) offset, + 0); if (errno) - return TARGET_XFER_EOF; + break; + if (readbuf) + memcpy (readbuf + n, buf.byte + skip, chunk); + } + if (writebuf) + { + memcpy (buf.byte + skip, writebuf + n, chunk); + errno = 0; + ptrace (PT_WRITE_D, pid, + (PTRACE_TYPE_ARG3)(uintptr_t) offset, + buf.word); + if (errno) + { + /* Using the appropriate one (I or D) is necessary for + Gould NP1, at least. */ + errno = 0; + ptrace (PT_WRITE_I, pid, + (PTRACE_TYPE_ARG3)(uintptr_t) offset, + buf.word); + if (errno) + break; + } } } - if (readbuf) - { - errno = 0; - buffer.word = ptrace (PT_READ_I, pid, - (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset, - 0); - if (errno) - return TARGET_XFER_EOF; - /* Copy appropriate bytes out of the buffer. */ - memcpy (readbuf, buffer.byte + (offset - rounded_offset), - partial_len); - } - - *xfered_len = partial_len; - return TARGET_XFER_OK; + *xfered_len = n; + return n ? TARGET_XFER_OK : TARGET_XFER_EOF; } case TARGET_OBJECT_UNWIND_TABLE: