This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: A sick idea - mmapped file output


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;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]