614 lines
15 KiB
C
614 lines
15 KiB
C
/* Copyright (C) 2021 Free Software Foundation, Inc.
|
|
Contributed by Oracle.
|
|
|
|
This file is part of GNU Binutils.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, 51 Franklin Street - Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/time.h>
|
|
|
|
#include "stopwatch.h"
|
|
|
|
/* parameters defining various tasks */
|
|
#define BUFSIZE 16384
|
|
#define NBLKS 1024
|
|
|
|
#define SIZE ((int)(16*1024*1024))
|
|
unsigned buffer[SIZE];
|
|
extern FILE *fid2;
|
|
|
|
/* ioerror - do some erroneous file IO operations */
|
|
int
|
|
ioerror ()
|
|
{
|
|
FILE *fp; /* FILE pointer for stdio */
|
|
char *fname = NULL;
|
|
char *ptr = NULL;
|
|
int fd; /* file descriptor for raw IO */
|
|
int fd2; /* file descriptor for raw IO */
|
|
int stat;
|
|
char buf[BUFSIZE];
|
|
unsigned long size = 0;
|
|
char sfn[23] = "";
|
|
|
|
/* Log the regular read */
|
|
wlog ("start of ioerror", NULL);
|
|
|
|
/* fname is set to NULL.
|
|
Use various calls to create
|
|
a file.
|
|
*/
|
|
|
|
fd = creat (fname, 0666);
|
|
fd = open (fname, 0666);
|
|
fd2 = 0;
|
|
fd = openat (fd2, fname, 0666);
|
|
fp = fopen (fname, "w");
|
|
fp = fopen ("/iotest", "w");
|
|
fp = NULL;
|
|
stat = fflush (fp);
|
|
stat = chmod (fname, 755);
|
|
stat = access (fname, 755);
|
|
fname = "/tmp/synprogXXXXXX";
|
|
strncpy (sfn, fname, sizeof (sfn));
|
|
fd = mkstemp (sfn);
|
|
stat = unlink (sfn);
|
|
stat = rename (fname, NULL);
|
|
unlink (fname);
|
|
fp = fopen (fname, "w");
|
|
stat = fclose (fp);
|
|
stat = fread (buf, 100, 2, fp);
|
|
stat = fwrite (buf, 100, 2, fp);
|
|
ptr = fgets (buf, size, fp);
|
|
read (10000, buf, 100);
|
|
write (10000, buf, 100);
|
|
stat = unlink (fname);
|
|
fname = NULL;
|
|
stat = mkdir (fname, 755);
|
|
stat = unlink (fname);
|
|
/*
|
|
These functions cannot be executed
|
|
if the File Pointer (fp) is set
|
|
to NULL. They generate segv failure
|
|
in actual call not inside of
|
|
the wrapper.
|
|
|
|
stat = fread(buf, size, 2, fp);
|
|
stat = fwrite(buf, size, 2, fp);
|
|
ptr = fgets(buf, size, fp);
|
|
stat = fputs(buf, fp);
|
|
stat = fprintf(fp, "%d\n", size);
|
|
stat = fseek(fp, size, size);
|
|
rewind(fp);
|
|
ftell(fp);
|
|
fpos_t pos;
|
|
stat = fsetpos(fp, &pos);
|
|
stat = fgetpos(fp, &pos);
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
/*=======================================================*/
|
|
|
|
/* iofile - do some file io operations */
|
|
int
|
|
iofile ()
|
|
{
|
|
FILE *fp; /* FILE pointer for stdio */
|
|
int k; /* temp value for loop */
|
|
int i;
|
|
char *buf;
|
|
hrtime_t start;
|
|
hrtime_t vstart;
|
|
char sfn[23] = "";
|
|
char *fname = "/tmp/synprogXXXXXX";
|
|
int ret;
|
|
int readCnt = 0;
|
|
int bRead = 0;
|
|
int writeCnt = 0;
|
|
int bWritten = 0;
|
|
int otherIOCnt = 0;
|
|
int bytes = 0;
|
|
|
|
start = gethrtime ();
|
|
vstart = gethrvtime ();
|
|
|
|
/* Log the event */
|
|
bytes = wlog ("start of iofile -- stdio", NULL);
|
|
bWritten += bytes;
|
|
writeCnt++;
|
|
|
|
strncpy (sfn, fname, sizeof (sfn));
|
|
ret = mkstemp (sfn);
|
|
otherIOCnt++;
|
|
if (ret == -1)
|
|
{
|
|
fprintf (stderr, "Unable to make a temporary name\n");
|
|
exit (1);
|
|
}
|
|
bytes = fprintf (stderr, "\tUsing %s as scratch file\n", sfn);
|
|
bWritten += bytes;
|
|
writeCnt++;
|
|
|
|
/* allocate a buffer for the reading */
|
|
/* note that this buffer is leaked! */
|
|
buf = (char *) malloc (BUFSIZE);
|
|
|
|
/* open the file */
|
|
fp = fdopen (ret, "w");
|
|
otherIOCnt++;
|
|
if (fp == NULL)
|
|
{
|
|
fprintf (stderr, "++ERROR opening %s, error %d\n", sfn, errno);
|
|
exit (1);
|
|
}
|
|
|
|
/* loop, writing the buffer to the file... */
|
|
for (i = 0; i < NBLKS; i++)
|
|
{
|
|
k = fwrite (buf, sizeof (char), BUFSIZE, fp);
|
|
writeCnt++;
|
|
if (k != BUFSIZE)
|
|
{
|
|
fprintf (stderr, "++ERROR writing %s, error %d\n", sfn, errno);
|
|
exit (1);
|
|
}
|
|
bWritten += k;
|
|
}
|
|
|
|
fclose (fp);
|
|
fp = NULL;
|
|
otherIOCnt++;
|
|
|
|
sprintf (buf, "fwrite: %d blocks of %d", i, BUFSIZE);
|
|
bytes = whrvlog (gethrtime () - start, gethrvtime () - vstart, buf, NULL);
|
|
bWritten += bytes;
|
|
writeCnt++;
|
|
|
|
|
|
/* now reopen the file, and read it */
|
|
start = gethrtime ();
|
|
vstart = gethrvtime ();
|
|
|
|
fp = fopen (sfn, "r");
|
|
otherIOCnt++;
|
|
if (fp == NULL)
|
|
{
|
|
fprintf (stderr, "++ERROR opening %s, error %d\n", sfn, errno);
|
|
exit (1);
|
|
}
|
|
i = 0;
|
|
for (;;)
|
|
{
|
|
k = fread (buf, sizeof (char), BUFSIZE, fp);
|
|
readCnt++;
|
|
if (k < 0)
|
|
fprintf (stderr, "++ERROR reading %s, error %d\n", sfn, errno);
|
|
|
|
|
|
if (k == 0)
|
|
{
|
|
/* close the file */
|
|
fclose (fp);
|
|
fp = NULL;
|
|
otherIOCnt++;
|
|
break;
|
|
|
|
}
|
|
else if (k != BUFSIZE)
|
|
{
|
|
/* short read */
|
|
sprintf (buf, "\tunexpecter short read %d on %s\n", k, sfn);
|
|
fprintf (stderr, buf);
|
|
bRead += k;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
/* bump the block counter */
|
|
i++;
|
|
bRead += k;
|
|
}
|
|
}
|
|
|
|
if (fp != NULL)
|
|
{
|
|
fclose (fp);
|
|
fp = NULL;
|
|
}
|
|
sprintf (buf, "fread: %d blocks of %d", i, BUFSIZE);
|
|
bytes = whrvlog (gethrtime () - start, gethrvtime () - vstart, buf, NULL);
|
|
bWritten += bytes;
|
|
writeCnt++;
|
|
|
|
bWritten += 99; /* the number of bytes are written by the next fprintf */
|
|
writeCnt++;
|
|
|
|
unlink (sfn);
|
|
otherIOCnt++;
|
|
fprintf (fid2, "X %14d %14d %17d %15d %17d iofile\n",
|
|
bRead, readCnt, bWritten, writeCnt, otherIOCnt);
|
|
return 0;
|
|
}
|
|
|
|
/* iotest - do various io syscalls */
|
|
int
|
|
iotest ()
|
|
{
|
|
char *fname = "/tmp/foobar";
|
|
int fd; /* file descriptor for raw IO */
|
|
int fd2; /* file descriptor for raw IO */
|
|
int k; /* temp value for loop */
|
|
char buf[BUFSIZE];
|
|
unsigned long size = 0;
|
|
int readCnt = 0;
|
|
int bRead = 0;
|
|
int writeCnt = 0;
|
|
int bWritten = 0;
|
|
int otherIOCnt = 0;
|
|
int bytes = 0;
|
|
|
|
/* Log the regular read */
|
|
bytes = wlog ("start of iotest", NULL);
|
|
bWritten += bytes;
|
|
writeCnt++;
|
|
|
|
/* create an empty file */
|
|
fd = creat (fname, 0666);
|
|
otherIOCnt++;
|
|
|
|
/* dup the file descriptor */
|
|
fd2 = dup (fd);
|
|
otherIOCnt++;
|
|
close (fd2);
|
|
otherIOCnt++;
|
|
close (fd);
|
|
otherIOCnt++;
|
|
|
|
/* now open the empty file */
|
|
fd = open (fname, O_RDONLY);
|
|
otherIOCnt++;
|
|
|
|
/* loop, reading into the buffer */
|
|
size = 0;
|
|
for (;;)
|
|
{
|
|
k = read (fd, buf, BUFSIZE);
|
|
readCnt++;
|
|
if (k < 0)
|
|
fprintf (stderr, "++ERROR reading %s, error %d\n", fname, errno);
|
|
else
|
|
{
|
|
size = size + k;
|
|
bRead += k;
|
|
}
|
|
if (k != BUFSIZE)
|
|
{
|
|
/* close the file */
|
|
close (fd);
|
|
fd = -1;
|
|
otherIOCnt++;
|
|
bRead += k;
|
|
|
|
/* short eread = EOF */
|
|
break;
|
|
}
|
|
}
|
|
if (fd != -1)
|
|
{
|
|
close (fd);
|
|
fd = -1;
|
|
}
|
|
bWritten += 99; /* the number of bytes are written by the next fprintf */
|
|
writeCnt++;
|
|
|
|
/* remove the file */
|
|
unlink (fname);
|
|
otherIOCnt++;
|
|
fprintf (fid2, "X %14d %14d %17d %15d %17d iotest\n",
|
|
bRead, readCnt, bWritten, writeCnt, otherIOCnt);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Memory mapping routines-
|
|
*
|
|
* Allocate and deallocate memory using mmap and malloc.
|
|
*
|
|
* There is one parameter--the total number of megabytes to write,
|
|
* written in as many 16 megabyte files as are needed
|
|
*/
|
|
|
|
unsigned char *start = (unsigned char*) 0x80000000;
|
|
unsigned char *stop;
|
|
int nblocks;
|
|
|
|
void
|
|
memorymap (int megabytes)
|
|
{
|
|
int readCnt = 0;
|
|
int bRead = 0;
|
|
int writeCnt = 0;
|
|
int bWritten = 0;
|
|
int otherIOCnt = 0;
|
|
int bytes;
|
|
|
|
/*
|
|
* First, see how much time it takes to mmap all the files.
|
|
*
|
|
* Second, pull in just a few pages of information to see how much
|
|
* time the "How much IBM do I hold?" question would take.
|
|
*
|
|
* Next, compare updating the database shared with updating it private
|
|
* and then recopying the changed segments.
|
|
|
|
* (We could catch the pages that we have altered by mapping the
|
|
* entire BIS read-only and then punching holes in it via an
|
|
* mprotect call as we catch segfaults. This gives us a list
|
|
* of the pages that we need to write, at the added expense of
|
|
* handling lots of interrupts.)
|
|
* (Notice that we don't test the case where we are adding to
|
|
* the BIS files. This is an interesting situation as we either
|
|
* have to open the last page past the last write point or reopen
|
|
* extendable in some way. We could do that by opening /dev/zero
|
|
* with MAP_ANON for addresses above our current usage point.
|
|
*/
|
|
|
|
int i;
|
|
stop = start + 1024 * 1024 * (long long) megabytes;
|
|
|
|
printf ("Creating %d random numbers\n", SIZE);
|
|
for (i = 0; i < SIZE; i++)
|
|
buffer[i] = random (); // set pseudo-bis to noise
|
|
printf ("Done creating random numbers\n");
|
|
|
|
|
|
/*
|
|
* Write a database consisting of 16 megabyte files.
|
|
* Each filename contains the memory address into which
|
|
* the file should be reloaded.
|
|
*/
|
|
|
|
printf ("Writing pseudo-bis files\n");
|
|
unsigned char* base = start;
|
|
nblocks = 0;
|
|
for (i = 0; i < megabytes; i += 16)
|
|
{
|
|
nblocks++;
|
|
// write data in 16MB files
|
|
char filename[256];
|
|
sprintf (filename, "bistest.%p.%d", base, i);
|
|
int fd = open (filename, O_CREAT | O_TRUNC | O_WRONLY, 0660);
|
|
otherIOCnt++;
|
|
if (fd == -1)
|
|
{
|
|
printf ("open of %s failed: %s\n", filename, strerror (errno));
|
|
exit (0);
|
|
}
|
|
bytes = write (fd, buffer, SIZE);
|
|
bWritten += bytes;
|
|
writeCnt++;
|
|
close (fd);
|
|
otherIOCnt++;
|
|
printf ("\twrote %d megabytes\n", i + 16);
|
|
base += 16 * 1024 * 1024;
|
|
}
|
|
printf ("Done writing files from %p to %p\n", start, stop);
|
|
|
|
int j;
|
|
|
|
printf ("Memory map all the files (private)\n");
|
|
for (i = 0; i < megabytes; i += 16)
|
|
{
|
|
unsigned char* base = start;
|
|
base += i * 1024 * 1024;
|
|
char filename[256];
|
|
sprintf (filename, "bistest.%p.%d", base, i);
|
|
int fd = open (filename, O_RDWR);
|
|
otherIOCnt++;
|
|
if (fd < 0)
|
|
printf ("open of %s failed: %s\n", filename, strerror (errno));
|
|
unsigned char *mp = (unsigned char*) mmap ((char*) base,
|
|
SIZE, PROT_READ | PROT_WRITE,
|
|
MAP_PRIVATE | MAP_FIXED, fd, 0);
|
|
if (mp == MAP_FAILED || mp != base)
|
|
{
|
|
printf ("mmap of %s failed: %s\n", filename, strerror (errno));
|
|
exit (1);
|
|
}
|
|
|
|
printf ("mapped %d bytes at %p\n", SIZE, base);
|
|
close (fd); // mmap will hold the file open for us
|
|
otherIOCnt++;
|
|
}
|
|
|
|
printf ("Mapping done\n");
|
|
fflush (stdout);
|
|
otherIOCnt++;
|
|
|
|
int ranlimit = 1000;
|
|
printf ("Access %d bytes at random\n", ranlimit);
|
|
int sum = 0;
|
|
for (i = 0; i < ranlimit; i++)
|
|
{
|
|
unsigned char *where = start +
|
|
(((unsigned long) random ()) % (stop - start));
|
|
sum += (int) *where;
|
|
}
|
|
printf ("Random byte access done\n");
|
|
|
|
ranlimit = 1000;
|
|
int ranrange = 256;
|
|
printf ("Alter %d random locations, %d bytes each (private)\n",
|
|
ranlimit, ranrange);
|
|
|
|
for (i = 0; i < ranlimit; i++)
|
|
{
|
|
unsigned char *where = start +
|
|
(((unsigned long) random ()) % (stop - start));
|
|
for (j = 0; j < ranrange; j++)
|
|
*where++ = j;
|
|
}
|
|
|
|
printf ("Memory alteration done\n");
|
|
fflush (stdout);
|
|
otherIOCnt++;
|
|
|
|
printf ("Copy all memory back to disk\n");
|
|
|
|
for (i = 0; i < megabytes; i += 16)
|
|
{
|
|
unsigned char* base = start;
|
|
base += i * 1024 * 1024;
|
|
char filename[256];
|
|
sprintf (filename, "bistest2.%p.%d", base, i);
|
|
int fd = open (filename, O_RDWR | O_CREAT | O_TRUNC, 0660);
|
|
otherIOCnt++;
|
|
if ((bytes = write (fd, base, SIZE)) == -1)
|
|
{
|
|
printf ("write of %s failed: %s\n", filename, strerror (errno));
|
|
exit (1);
|
|
}
|
|
bWritten += bytes;
|
|
writeCnt++;
|
|
close (fd);
|
|
otherIOCnt++;
|
|
}
|
|
|
|
printf ("Disk copy complete\n");
|
|
fflush (stdout);
|
|
otherIOCnt++;
|
|
|
|
printf ("Unmap all segments\n");
|
|
for (i = 0; i < megabytes; i += 16)
|
|
{
|
|
unsigned char* base = start;
|
|
base += i * 1024 * 1024;
|
|
if (munmap ((char*) base, SIZE) == -1)
|
|
{
|
|
printf ("munmap failed: %s\n", strerror (errno));
|
|
exit (1);
|
|
}
|
|
printf ("unmapped %d bytes at %p\n", SIZE, base);
|
|
}
|
|
printf ("Segment unmapping complete\n");
|
|
fflush (stdout);
|
|
otherIOCnt++;
|
|
|
|
printf ("Remap all segments as shared\n");
|
|
for (i = 0; i < megabytes; i += 16)
|
|
{
|
|
unsigned char* base = start;
|
|
base += i * 1024 * 1024;
|
|
char filename[256];
|
|
sprintf (filename, "bistest.%p.%d", base, i);
|
|
int fd = open (filename, O_RDWR);
|
|
otherIOCnt++;
|
|
char* mp = mmap ((char*) base, SIZE, PROT_READ | PROT_WRITE,
|
|
MAP_SHARED | MAP_FIXED, fd, 0);
|
|
if (mp == MAP_FAILED || (unsigned char*) mp != base)
|
|
{
|
|
printf ("re mmap of %s failed: %s\n", filename, strerror (errno));
|
|
exit (1);
|
|
}
|
|
printf ("remapped %d bytes at %p\n", SIZE, base);
|
|
close (fd); // mmap will hold the file open for us
|
|
otherIOCnt++;
|
|
}
|
|
printf ("Remapping complete\n");
|
|
fflush (stdout);
|
|
otherIOCnt++;
|
|
|
|
ranlimit = 1000;
|
|
ranrange = 256;
|
|
printf ("Alter %d random locations, %d bytes each (shared)\n",
|
|
ranlimit, ranrange);
|
|
for (i = 0; i < ranlimit; i++)
|
|
{
|
|
unsigned char* where = start +
|
|
(((unsigned long) random ()) % (stop - start));
|
|
for (j = 0; j < ranrange; j++)
|
|
*where++ = j;
|
|
}
|
|
printf ("Memory alteration done\n");
|
|
fflush (stdout);
|
|
otherIOCnt++;
|
|
|
|
printf ("Unmap all segments\n");
|
|
for (i = 0; i < megabytes; i += 16)
|
|
{
|
|
unsigned char *base = start;
|
|
base += i * 1024 * 1024;
|
|
if (munmap ((char*) base, SIZE) == -1)
|
|
{
|
|
printf ("munmap failed: %s\n", strerror (errno));
|
|
exit (1);
|
|
}
|
|
printf ("unmapped %d bytes at %p\n", SIZE, base);
|
|
}
|
|
printf ("Segment unmapping complete\n");
|
|
fflush (stdout);
|
|
otherIOCnt++;
|
|
|
|
base = start;
|
|
|
|
for (i = 0; i < megabytes; i += 16)
|
|
{
|
|
// write data in 16MB files
|
|
char filename[256];
|
|
sprintf (filename, "bistest.%p.%d", base, i);
|
|
if (unlink (filename) != 0)
|
|
{
|
|
printf ("unlink of %s failed: %s\n", filename, strerror (errno));
|
|
}
|
|
base += 16 * 1024 * 1024;
|
|
otherIOCnt++;
|
|
}
|
|
|
|
for (i = 0; i < megabytes; i += 16)
|
|
{
|
|
unsigned char* base = start;
|
|
base += i * 1024 * 1024;
|
|
char filename[256];
|
|
sprintf (filename, "bistest2.%p.%d", base, i);
|
|
if (unlink (filename) != 0)
|
|
{
|
|
printf ("unlink of %s failed: %s\n", filename, strerror (errno));
|
|
}
|
|
otherIOCnt++;
|
|
}
|
|
bWritten += 102; /* the number of bytes are written by the next fprintf */
|
|
writeCnt++;
|
|
|
|
fflush (fid2);
|
|
otherIOCnt++;
|
|
|
|
/* Record accounting record */
|
|
fprintf (fid2, "X %14d %14d %17d %15d %17d memorymap\n",
|
|
bRead, readCnt, bWritten, writeCnt, otherIOCnt);
|
|
printf ("Deleted scratch files\n");
|
|
}
|