This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: A sick idea - mmapped file output
- To: Zack Weinberg <zackw at stanford dot edu>
- Subject: Re: A sick idea - mmapped file output
- From: Richard Henderson <rth at cygnus dot com>
- Date: Thu, 2 Nov 2000 23:30:05 -0800
- Cc: gcc at gcc dot gnu dot org
- References: <20001102214053.G322@wolery.stanford.edu>
On Thu, Nov 02, 2000 at 09:40:53PM -0800, Zack Weinberg wrote:
> - Do you have any suggestions for what to do when you run off the end
> of the mapping? Bonus points if your idea doesn't involve MAP_FIXED,
> and/or if it works with the signal approach.
I don't think any sorts of timing are valuable unless you
handle the overflow case somehow. Further, you should test
against a straightforward write implementation so that you
don't get to thinking that mmap is better than it is.
Further, the output file will basicly never be a multiple
of the chunk size, so you should have to handle that as well.
I've appended a program to do just that. The mmap case is
basicly the same as your "clever" case. There is an if 0
to control whether or not MAP_FIXED is used (for the re-map
only, which I imagine works everywhere).
With this I get:
i686-linux (hz=100)
usr sys wall
mmap 2 6 7
write 3 3 7
alphaev6-linux (hz=1024)
usr sys wall
mmap 25 30 55
write 30 21 51
sparc-solaris2.5.1 (hz=?)
usr sys wall
mmap 8 3 18
write 7 5 45
mips-irix6.5 (hz=?)
usr sys wall
mmap 5 4 10
write 6 3 9
powerpc-aix3.4 (hz=?)
usr sys wall
mmap 4 1 19
write 3 6 11
r~
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/times.h>
#include <string.h>
#define MAPSZ (1024 * 1024)
#define WRTSZ (32 * 1024)
#define ITERATIONS ((3 * MAPSZ - 8193) / 27)
static const char letters[] = "abcdefghijklmnopqrstuvwxyz\n";
struct mmap_status
{
char *cur, *base;
off_t base_off;
int fd;
};
static struct mmap_status mmap_status;
static void
mmap_open(void)
{
int fd;
char *base;
fd = open("out.m", O_RDWR|O_CREAT|O_TRUNC, 0666);
ftruncate (fd, MAPSZ);
base = mmap(0, MAPSZ, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
mmap_status.cur = base;
mmap_status.base = base;
mmap_status.base_off = 0;
mmap_status.fd = fd;
}
static void
mmap_generate(const char *str, size_t len)
{
size_t left = MAPSZ - (mmap_status.cur - mmap_status.base);
if (__builtin_expect (left < len, 0))
{
do
{
char *newbase, *oldbase;
memcpy (mmap_status.cur, str, left);
len -= left;
mmap_status.base_off += MAPSZ;
ftruncate (mmap_status.fd, mmap_status.base_off + MAPSZ);
#if 0
oldbase = mmap_status.base;
newbase = mmap (oldbase, MAPSZ, PROT_READ|PROT_WRITE,
MAP_SHARED, mmap_status.fd, mmap_status.base_off);
mmap_status.cur = newbase;
if (__builtin_expect (newbase != oldbase, 0))
{
mmap_status.base = newbase;
if (oldbase < newbase)
{
left = newbase - oldbase;
if (left > MAPSZ)
left = MAPSZ;
}
else
{
left = (oldbase + MAPSZ) - newbase;
if (left < MAPSZ)
oldbase += MAPSZ - left;
else
left = MAPSZ;
}
munmap (oldbase, left);
}
#else
mmap_status.cur = mmap_status.base;
mmap (mmap_status.base, MAPSZ, PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_FIXED, mmap_status.fd, mmap_status.base_off);
#endif
left = MAPSZ;
}
while (len > left);
}
memcpy(mmap_status.cur, str, len);
mmap_status.cur += len;
}
static void
mmap_close(void)
{
ftruncate (mmap_status.fd, ((mmap_status.cur - mmap_status.base)
+ mmap_status.base_off));
}
struct write_status
{
char buf[WRTSZ];
char *cur;
int fd;
};
static struct write_status write_status;
static void
write_open(void)
{
write_status.fd = open("out.w", O_RDWR|O_CREAT|O_TRUNC, 0666);
write_status.cur = write_status.buf;
}
static void
write_generate(const char *str, size_t len)
{
size_t left = WRTSZ - (write_status.cur - write_status.buf);
if (__builtin_expect (left < len, 0))
{
do
{
memcpy (write_status.cur, str, left);
len -= left;
write_status.cur = write_status.buf;
write(write_status.fd, write_status.buf, WRTSZ);
left = WRTSZ;
}
while (len > left);
}
memcpy(write_status.cur, str, len);
write_status.cur += len;
}
static void
write_close(void)
{
write (write_status.fd, write_status.buf,
write_status.cur - write_status.buf);
}
static void
test_mmap(void)
{
int i;
mmap_open ();
for (i = 0; i < ITERATIONS; ++i)
mmap_generate (letters, sizeof(letters)-1);
mmap_close ();
}
static void
test_write(void)
{
int i;
write_open ();
for (i = 0; i < ITERATIONS; ++i)
write_generate (letters, sizeof(letters)-1);
write_close();
}
int
main()
{
struct tms a, b;
clock_t aw, bw;
setvbuf (stdout, 0, _IOLBF, 0);
fputs("\tusr\tsys\twall\n", stdout);
aw = times(&a);
test_mmap();
bw = times(&b);
printf ("mmap\t%d\t%d\t%d\n",
b.tms_utime - a.tms_utime,
b.tms_stime - a.tms_stime,
bw - aw);
aw = times(&a);
test_write();
bw = times(&b);
printf ("write\t%d\t%d\t%d\n",
b.tms_utime - a.tms_utime,
b.tms_stime - a.tms_stime,
bw - aw);
return 0;
}