Finding slowdowns in pkg_install (continuations of previous threads)

Tim Kientzle kientzle at freebsd.org
Sun Jul 15 00:17:46 UTC 2007


>    The following blog post has all of my commentary on the results I 
> have: 
> <http://blogs.freebsdish.org/gcooper/2007/07/14/modifications-to-pkg_install-the-positive-and-negative-implications/>. 

> I tried to unroll strcmp a bit by checking for the first character of the
 > command, then run strcmp ...

There's a somewhat more straightforward optimization that
relies on this same idea:

switch(cmd[0]) {
case 'c':
     /* Commands that start with 'c' */
     if (strcmp(cmd, 'cwd') == 0)
	return (CMD_CWD);
     /* FALLTHROUGH */
case 'd':
     /* Commands that start with 'd' */

     .... etc....
     /* FALLTHROUGH */
default:
     /* Unrecognized command. */
}

This is a little cleaner and easier to read
and may even be faster than the code you
presented in your blog.  Note that the fall through
ensures that all unrecognized commands end up at
the same place.  If unrecognized commands are
very rare (they should be), then the fallthrough
is not a performance issue.

> /** malloc buffer large enough to hold +CONTENTS **/
> 
> while(!feof(file_p)) {
> 
>     /** add content via fgetc **/
> }

Yuck.  Try this instead:

    struct stat st;
    int fd;
    char *buff;

    fd = open(file);
    fstat(fd, &st);
    buff = malloc(st.st_size + 1);
    read(fd, buff, st.st_size);
    buff[st.st_size] = '\0';
    close(fd);

Plus some error checking, of course.  You can
use stdio if you prefer:

    FILE *f;

    f = fopen(file, "r");
    fstat(fileno(f), &st);
    buff = malloc(st.st_size + 1);
    fread(buff, 1, st.st_size, f);
    buff[st.st_size] = '\0';
    fclose(f);

Either way, this is a lot more efficient than
tens of thousands of calls to fgetc().

Cheers,

Tim Kientzle


More information about the freebsd-hackers mailing list