Re: enhanced swaptest

J.J. Burgess (92jjb@eng.cam.ac.uk)
Sun, 5 May 1996 19:41:18 +0100 (BST)


Here is an updated swaptest program, which incorporates a few bug fixes
and enhancements, please test it if you wish and send me some bug
reports. I may soon upload this to sunsite etc, if theres no problems.

1.summary of findings with the program:
2.Striping swap does increase general clean data swap performance
3.It does not improve the modified,dirty swapped data.
4.Random access of swapped data has no perfmance at all.

(4) explains why some applications will probably always need a large
amount of RAM to run at a reasonable speed. Other with sequential access
however may be speeded up a great deal if we can improve the swapping
algorithms. I am currently finishing my Master's and so won't have time
to do any serious work on it. (for another month)

Also thanks to Andreas for implementing a lot of extra features.
(I fixed your 'random access' mode - it didn't work)

/* swaptest.c 0.3 (C) Jon Burgess 92jjb@eng.cam.ac.uk
* heavily modified by
* Andreas Koppenhoefer <koppenas@informatik.uni-stuttgart.de>.
*
* Tests the performance of the linux swap system
* Generates a block of random data, and times how long it takes to read
* and modify the whole lot.
* Not surprisingly, the 'in memory' tests are very high, dropping
* rapidly once the memory block exceeds the available RAM
*/

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>

static off_t ram_size;
static int verbose = 0;
static const char *progname;

void
do_test (off_t test_size, int mode, int iterations, int step)
{
char *buf, *fill_ptr;
int file;
int i, ptr, c;
static char junk = 0;
struct timeval e1, e2;
double elapsed, speed;
double sum_elapsed = 0.0, sum_speed = 0.0;
int r_size;
off_t *r;

if (step * 1000 > test_size)
{
int new_step = test_size / 1000;
fprintf (stderr,
"memory access granularity %d too rough - using %d instead\n",
step, new_step);
step = new_step;
}
buf = (char *) malloc (test_size);
if (!buf)
{ /* on linux this should never happen */
perror ("malloc");
exit (2);
}

file = open ("/dev/urandom", O_RDONLY, 0);
if (file == -1)
{
perror ("problem with /dev/urandom, using rand()");
/*exit (1);*/
}

if ((file != -1) && (read (file, buf, 1024) != 1024))
{
perror ("read from /dev/urandom failed, uning rand()");
/*exit (1);*/
}
else /* Now use rand() instead */
{
for (fill_ptr=buf; fill_ptr<(buf+1024); fill_ptr++)
*fill_ptr = rand() / (RAND_MAX >> 8);
}

if (mode & 2) {
/* initialize random access array */
r_size = test_size / step;
r = (off_t *) malloc(sizeof(off_t)*r_size);
if (!r)
{ /* on linux this should never happen */
perror ("malloc");
exit (2);
}

/* init array of adresses */
for (ptr =0, i = 0; i < r_size; i++, ptr+=step)
r[i] = ptr;
/* swap each element with another one choosen randomly*/
for (i = r_size; --i >= 0; )
{
off_t tmp;
ptr = (int) (((double)r_size)*rand()/ RAND_MAX);
tmp = r[ptr];
r[ptr] = r[i];
r[i] = tmp;
}
}

/* generate 1MB of repeated random data */
for (ptr = 1024; (ptr << 1) < test_size && ptr < (1024*1024); ptr <<= 1)
{
/* fprintf (stderr, "memcpy (%08x, %08x, %08x)\n", buf+ptr, buf, ptr);*/
memcpy (buf+ptr, buf, ptr);
}

while (ptr < test_size)
{
off_t len = test_size - ptr;
if (len > (1024*1024))
len = (1024*1024);
/* fprintf (stderr,
"memcpy (%08x, %08x, %08x)\n",buf+ptr, buf+ptr-len,len);*/
memcpy(buf+ptr, buf+ptr-len, len);
ptr+=len;
}

for (i = 0; i <= iterations; i++)
{
if (i == 1)
{
(void) gettimeofday (&e1, NULL);
}
(void) gettimeofday (&e1, NULL);

if (mode & 2)
{
for (ptr = 0; ptr < r_size; ptr++)
{
junk ^= *(r[ptr] + buf);
if (mode & 1)
(int) *(r[ptr] + buf) = junk;
}
}
else
{
for (ptr = 0; ptr < test_size; ptr += step)
{
junk ^= *(ptr + buf);
if (mode & 1)
(int) *(ptr + buf) = junk;
}
}
(void) gettimeofday (&e2, NULL);

elapsed = e2.tv_sec - e1.tv_sec +
((double)(e2.tv_usec - e1.tv_usec)) / 1000000.0;
speed = ((double)test_size) / (1024 * 1024) / elapsed;

if (verbose)
fprintf(stderr,
" pass %4d: %6.2lf MB in %8.3lf seconds =%7.2lf MB/sec\n",
i, ((double)test_size) / (1024 * 1024),
elapsed, speed);
/* We don't time the first iteration, since this is swapping other
things as well like daemons.
*/
if (i > 0)
{
sum_elapsed += elapsed;
sum_speed += speed;
}
}

fprintf(stderr,
"%4d iterations: %6.2lf MB in %8.3lf seconds =%7.2lf MB/sec\n",
iterations,
((double)test_size) / (1024 * 1024),
sum_elapsed / iterations, sum_speed / iterations);
if (mode & 2)
free(r);
free (buf);
}

void
usage (void)
{
fprintf (stderr, "usage: %s [ -t ] [ -m <mode> ] [ -i <iteration> ]\n"
"\t [ -s <granularity> ] [ <size> ... ]\n"
"options:\n"
"\t-t run test with diffrent sizes\n"
"\t-m <mode> mode access type order\n"
"\t 0 read only sequential (default)\n"
"\t 1 read&modify sequential\n"
"\t 2 read only random\n"
"\t 3 read&modify random\n"
"\t-i <iteration> iteration loop count (default: 1)\n"
"\t-s <granularity> step width for accessing memory pages (default: 256)\n"
"\t-v verbose - give additional information\n"
"\t-h help - you'll get this text\n"
"Any additional nummeric argument treated as size of memory in MB\n"
"to be checked in sequence (default: %5.2lf).\n",
progname, ((double) ram_size) / (1024 * 1024));
}

int
main (int argc, char *argv[])
{
struct stat info;
off_t mem_size = 0;
char c;
int mode = 0, step = 256;
int iterations = 1;
int test_flag = 0;

progname = *argv;
/* Find out the memory size */
if (stat ("/proc/kcore", &info))
{
perror ("/proc/kcore");
exit (1);
}

if (!(ram_size = info.st_size))
{
perror ("cannot stat /proc/kcore");
exit (1);
}

while ((c = getopt (argc, argv, "vthm:i:s:")) >= 0)
{
switch (c)
{
case 't':
test_flag++;
break;
case 'v':
verbose++;
break;
case 'm':
mode = atoi (optarg);
if (mode < 0 || mode > 3)
{
fprintf (stderr,
"unkown mode %d - should be in the range 0..3d\n",
mode);
usage ();
exit (1);
}
break;
case 's':
step = atoi (optarg);
if (step < 1)
{
fprintf (stderr, "bad step granularity %d: must be positive\n",
step);
usage ();
exit (1);
}
break;
case 'i':
iterations = atoi (optarg);
if (iterations < 1)
{
fprintf (stderr, "number of iteration must be positive: %d\n",
iterations);
usage ();
exit (1);
}
break;
case 'h':
usage ();
exit (0);
default:
usage ();
exit (1);
}
}
fprintf (stderr, "%s: physical RAM size %5.2lf MB\n",
progname, ((double) ram_size) / (1024 * 1024));
fprintf (stderr, "%s pages of data in %s order - iteration loop count: %d\n",
mode & 1 ? "modifying" : "reading",
mode & 2 ? "random" : "sequential",
iterations);

if (optind >= argc)
{
if (test_flag)
{
do_test (ram_size / 4, mode, iterations, step);
do_test (ram_size/1.5, mode, iterations, step);
do_test (ram_size, mode, iterations, step);
do_test (ram_size*1.5, mode, iterations, step);
do_test (ram_size*2, mode, iterations, step);
}
else
do_test (ram_size, mode, iterations, step);
}
else
while (optind < argc)
{
mem_size = (off_t) (atof (argv[optind++]) * (1024 * 1024)) & ~0xffff;
if (mem_size < 4096 || mem_size > 1e9 || mem_size > 16*ram_size)
{
fprintf (stderr, "bad memsize: %5.2lf MB\n",
((double)mem_size) / (1024 * 1024));
usage ();
exit (1);
}
if (test_flag)
{
do_test (mem_size / 4, mode, iterations, step);
do_test (mem_size/1.5, mode, iterations, step);
do_test (mem_size, mode, iterations, step);
do_test (mem_size*1.5, mode, iterations, step);
do_test (mem_size*2, mode, iterations, step);
}
else
do_test (mem_size, mode, iterations, step);
}
exit (0);
}

Thanks.

.. . . . . . . . . . . . . . ..
:: : : Jon Burgess 01223-461907 : : ::
:: : jjb1003@cam.ac.uk : : ::
:: : : : : : : : : : : : : : ::