/* Copyright (C) 2021-2024 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 #include #include #include #include #include #include #include #include #include #include #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"); }