| /* 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 <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"); |
| } |