Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 27 Jan 1997 05:34:36 +1100
From:      Bruce Evans <bde@zeta.org.au>
To:        bde@zeta.org.au, phk@critter.dk.tfs.com
Cc:        current@freebsd.org, dg@root.com, swallace@ece.uci.edu
Subject:   Re: exec bug
Message-ID:  <199701261834.FAA05327@godzilla.zeta.org.au>

next in thread | raw e-mail | index | archive | help
>>What is the library malloc()+free() doing to be 5 times slower than
>>read+lseek()?  The kernel malloc() is fast enough to use :-).  It takes
>>a couple of usec for small allocations.
>
>You're timing the initialization and allocation of the "page table".
>Try adding
>	 free(malloc(1));
>before you take the first timestamp.

No, I'm iterating 1000 times, so the malloc initialization time is in
the noise (unless it is done every time).  Also, printf() probably calls
malloc() so the malloc initization time is already paid for.  Here's a
version with more knobs to twiddle.

I also added some timing to execve().  There doesn't seem to be any
pagefault penalty, but the overhead for vm_mmap()+vm_map_remove() in
the kernel seems to be about the same as for doing a read() from user
space!  It's hard to compare the times because the kernel code has
some chance of staying in a cache, while the user code has no chance
of being in a cache for the first iteration and too high a chance for
subsequent iterations.  These times are on a 486/33:

vm_mmap for /bin/cat:				110-134 usec
vm_map_remove for /bin/cat:			51-52
user mmap (1000 iterations, access 32 bytes):	221-228
user mmap (1    iteration,  access 32 bytes):	616-4078 (normally < 700)
user read (1000 iterations, access 32 bytes):	132-159 (not preceded by mmap)
user read (1    iteration,  access 32 bytes):	415-512
malloc+r  (1000 iterations, access 32 bytes):	428-435 (by itself)
malloc+r  (1    iteration,  access 32 bytes):	2867-6404 (normally about 3000)

The malloc initialization overhead dominates the time for the malloc+read
1-iteration case.

Bruce

#include <sys/types.h>
#include <sys/mman.h>
#include <sys/time.h>

#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#define	PAGE_SIZE	4096

int main(int argc, char **argv)
{
	size_t access_size;
	char buf[PAGE_SIZE];
	int fd, i, j, niter;
	char *malbuf;
	unsigned mask;
	caddr_t p;
	struct timeval tv0, tv1;

	access_size = argc > 1 ? strtol(argv[1], NULL, 0) : 32;
	niter = argc > 2 ? strtol(argv[2], NULL, 0) : 1000;
	mask = argc > 3 ? strtol(argv[3], NULL, 0) : 7;
	fd = open("/bin/cat", O_RDONLY);
	if (fd == -1)
		perror("open");

	if (!(mask & 1))
		goto over_mmap_test;
	if (gettimeofday(&tv0, NULL) != 0)
		perror("gettimeofday 1");
	for (i = 0; i < niter; ++i) {
		p = mmap((caddr_t)0, PAGE_SIZE, PROT_READ, 0, fd, (off_t)0);
		if (p == MAP_FAILED)
			perror("mmap");
		for (j = 0; j < access_size; j += sizeof(int))
			*(volatile int *)(p + j);
		if (munmap(p, PAGE_SIZE) != 0)
			perror("munmap");
	}
	if (gettimeofday(&tv1, NULL) != 0)
		perror("gettimeofday 2");
	printf("mmap time = %.0f usec\n",
	       (1e6 * (tv1.tv_sec - tv0.tv_sec) + (tv1.tv_usec - tv0.tv_usec))
	       / niter);
over_mmap_test: ;

	if (!(mask & 2))
		goto over_read_test;
	if (gettimeofday(&tv0, NULL) != 0)
		perror("gettimeofday 3");
	for (i = 0; i < niter; ++i) {
		if (read(fd, buf, access_size) != access_size)
			perror("read");
		if (lseek(fd, (off_t)0, SEEK_SET) != 0)
			perror("lseek");
	}
	if (gettimeofday(&tv1, NULL) != 0)
		perror("gettimeofday 4");
	printf("read time = %.0f usec\n",
	       (1e6 * (tv1.tv_sec - tv0.tv_sec) + (tv1.tv_usec - tv0.tv_usec))
	       / niter);
over_read_test: ;

	if (!(mask & 4))
		goto over_malloc_read_test;
	if (gettimeofday(&tv0, NULL) != 0)
		perror("gettimeofday 5");
	for (i = 0; i < niter; ++i) {
		/* malloc()/free() is much slower than read()! */
		malbuf = malloc(PAGE_SIZE);
		if (malbuf == NULL)
			perror("malloc");
		if (read(fd, malbuf, access_size) != access_size)
			perror("read");
		if (lseek(fd, (off_t)0, SEEK_SET) != 0)
			perror("lseek");
		free(malbuf);
	}
	if (gettimeofday(&tv1, NULL) != 0)
		perror("gettimeofday 6");
	printf("malloc+read time = %.0f usec\n",
	       (1e6 * (tv1.tv_sec - tv0.tv_sec) + (tv1.tv_usec - tv0.tv_usec))
	       / niter);
over_malloc_read_test: ;

	return 0;
}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199701261834.FAA05327>