From nobody@FreeBSD.ORG Fri Apr  9 19:36:50 1999
Return-Path: <nobody@FreeBSD.ORG>
Received: by hub.freebsd.org (Postfix, from userid 32767)
	id 2B10514EFF; Fri,  9 Apr 1999 19:36:50 -0700 (PDT)
Message-Id: <19990410023650.2B10514EFF@hub.freebsd.org>
Date: Fri,  9 Apr 1999 19:36:50 -0700 (PDT)
From: wolman@cs.washington.edu
Sender: nobody@FreeBSD.ORG
To: freebsd-gnats-submit@freebsd.org
Subject: [PATCH] performance bug fix to fgets() routine
X-Send-Pr-Version: www-1.0

>Number:         11052
>Category:       misc
>Synopsis:       [PATCH] performance bug fix to fgets() routine
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    sobomax
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Apr  9 19:40:00 PDT 1999
>Closed-Date:    Mon Feb 5 02:10:47 PST 2001
>Last-Modified:  Mon Feb 05 02:12:29 PST 2001
>Originator:     Alec Wolman
>Release:        3.1
>Organization:
UW, CSE Department
>Environment:
FreeBSD miles.cs.washington.edu 3.1-19990403-STABLE FreeBSD 3.1-19990403-STABLE #0: Sun Apr  4 23:54:44 PDT 1999     wolman@miles.cs.washington.edu:/usr/src/sys/compile/MILES  i386
>Description:
The fgets routine touches all the string data twice, once with 
a call to the memchr() routine, and then again with a call to memcpy().
Using memccpy() eliminates this problem.

>How-To-Repeat:
N/A.

>Fix:
The following patch fixes the problem.  It have tested the patch,
and the measured the performance improvement for lines whose length
was 130 characters on average.  The new version is 15% faster on
my P6/200.

I would be happy to email the diff to anyone who is interested, since
cut & paste destroys the TABs.

--- fgets.c.orig        Sat Apr 11 00:40:43 1998
+++ fgets.c     Fri Apr  9 19:23:11 1999
@@ -59,8 +59,8 @@
        register FILE *fp;
 {
        register size_t len;
-       register char *s;
-       register unsigned char *p, *t;
+       register char *s,*t;
+       register unsigned char *p;
 
        if (n <= 0)             /* sanity check */
                return (NULL);
@@ -93,19 +93,17 @@
                 */
                if (len > n)
                        len = n;
-               t = memchr((void *)p, '\n', len);
+               t = memccpy((void *)s, (void *)p, '\n', len);
                if (t != NULL) {
-                       len = ++t - p;
+                       len = t - s;
                        fp->_r -= len;
-                       fp->_p = t;
-                       (void)memcpy((void *)s, (void *)p, len);
+                       fp->_p += len;
                        s[len] = 0;
                        FUNLOCKFILE(fp);
                        return (buf);
                }
                fp->_r -= len;
                fp->_p += len;
-               (void)memcpy((void *)s, (void *)p, len);
                s += len;
                n -= len;
        }



>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->sobomax 
Responsible-Changed-By: sobomax 
Responsible-Changed-When: Fri Feb 2 01:37:58 PST 2001 
Responsible-Changed-Why:  
I'll take this. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=11052 

From: Maxim Sobolev <sobomax@FreeBSD.org>
To: freebsd-gnats-submit@FreeBSD.org, wolman@cs.washington.edu
Cc:  
Subject: Re: misc/11052: [PATCH] performance bug fix to fgets() routine
Date: Fri, 02 Feb 2001 19:48:33 +0200

 This is a multi-part message in MIME format.
 --------------91AE5CA0C2FDE389D95CC373
 Content-Type: text/plain; charset=koi8-r
 Content-Transfer-Encoding: 7bit
 
 It's confusing, but my tests shown that your version actually is *slower* than
 original by 40%, so apparently memccpy() is not quite optimized for speed
 comparing to memcpy(). With this message I attaching simple test program which
 I used to measure performance and final version of the patch used in
 benchmarks. I benchmarked it on the large set of files (400MB or so), both
 binary and text, using the following command:
 
 $ find /somewhere -type f | xargs cat | time ./fgets_bench
 
 Please check and report if you can confirm my findings, so I'll close this pr.
 
 Thanks!
 
 -Maxim
 
 --------------91AE5CA0C2FDE389D95CC373
 Content-Type: text/plain; charset=koi8-r;
  name="fg.diff"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: inline;
  filename="fg.diff"
 
 --- fgets.c	2001/02/02 15:51:27	1.1
 +++ fgets.c	2001/02/02 17:13:10
 @@ -61,8 +61,8 @@
  	register FILE *fp;
  {
  	register size_t len;
 -	register char *s;
 -	register unsigned char *p, *t;
 +	register char *s, *t;
 +	register unsigned char *p;
  
  	if (n <= 0)		/* sanity check */
  		return (NULL);
 @@ -95,19 +95,16 @@
  		 */
  		if (len > n)
  			len = n;
 -		t = memchr((void *)p, '\n', len);
 +		t = memccpy((void *)s, (void *)p, '\n', len);
  		if (t != NULL) {
 -			len = ++t - p;
 +			len = t - s;
  			fp->_r -= len;
 -			fp->_p = t;
 -			(void)memcpy((void *)s, (void *)p, len);
 -			s[len] = 0;
 -			FUNLOCKFILE(fp);
 -			return (buf);
 +			fp->_p += len;
 +			s += len;
 +			break;
  		}
  		fp->_r -= len;
  		fp->_p += len;
 -		(void)memcpy((void *)s, (void *)p, len);
  		s += len;
  		n -= len;
  	}
 
 --------------91AE5CA0C2FDE389D95CC373
 Content-Type: text/plain; charset=koi8-r;
  name="bench.c"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: inline;
  filename="bench.c"
 
 #include <stdio.h>
 
 int main()
 {
 	FILE *file;
 	char buf[512];
 
 	file = fdopen(0, "r");
 	while (fgets(buf, 512, file) != NULL);
 	return 0;
 }
 
 --------------91AE5CA0C2FDE389D95CC373--
 
 
State-Changed-From-To: open->closed 
State-Changed-By: sobomax 
State-Changed-When: Mon Feb 5 02:10:47 PST 2001 
State-Changed-Why:  
Closed at originator's requiest (the patch proposed actually slows down things 
instead of speeding up.) 

http://www.freebsd.org/cgi/query-pr.cgi?pr=11052 
>Unformatted:
