/* grabmem -- allocates, initialises, and immediately frees a block of memory. * Copyright 2001 by Paul Jankowski version 2.2, 2001/08/21 * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as published * by the Free Software Foundation. * * 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, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA */ #include "grabmem.h" int main(int argc, char *argv[]) { double numbytes; /* On a 64-bit system, this should be a 64-bit float. */ char *memptr; int stride = 0, quiet = ISQUIET, naughty = ISNAUGHTY, bastard = ISBASTARD; if ((numbytes = parseargs(argc, argv, &stride, &naughty, &bastard, &quiet)) < 0) terminate(numbytes); if (allocate(&memptr, numbytes, quiet)) terminate(BADALLOC); initialise(&memptr, numbytes, stride, bastard); deallocate(&memptr, naughty); terminate(0); return 0; /* Included for completeness. */ } /* terminate: exit(), perhaps printing a useful error message. */ void terminate(int errorcode) { if (errorcode == BADNUM) fprintf(stderr, "grabmem: I don't understand the size you specified.\n\n"); else if (errorcode == BADSTRIDE) fprintf(stderr, "grabmem: I don't understand that stride.\n\n"); else if (errorcode == BADARGS) fprintf(stderr, "grabmem: I don't know what you want.\n\n"); else if (errorcode == BADALLOC) fprintf(stderr, "grabmem: malloc() failed: not enough free memory.\n"); if (errorcode != 0 && errorcode != BADALLOC) printf("%s\n", VER_STRING); if (errorcode == HELP || errorcode == BADSTRIDE || errorcode == BADNUM || errorcode == BADARGS) printhelp(); if (errorcode == HELP || errorcode == VERSION) errorcode = 0; fflush(stderr); fflush(stdout); exit (errorcode); } int printhelp() { printf("\n\ Allocates and initialises a block of memory, then immediately frees it.\n\ \n\ Usage: grabmem [options] size\n\ \n\ Options: -h, --help Print this help and exit\n\ -v, --version Print a short version string and exit\n\ -q, --quiet Do not print status information while allocating memory\n\ -s, --stride n Write a byte only once every n bytes (default=%d)\n\ -n, --nasty Do not exit after allocating and initialising memory\n\ -b, --bastard Enter an infinite initialisation loop -- doing this with a grabsize close to the size of system memory is not recommended. \n\ Size and stride are positive numbers given in bytes, and can be modified by\n\ the usual suffices (k, M, G, T, P, E, Z, Y), eg 64k, 4G, etc, or with the\n\ exponent operator (e or E), eg 1E6, 8e2E, etc.\n", getpagesize()); return 0; } /* parseargs: scan the command-line parameters and extract useful information. * Return the number of bytes of memory to be allocated (including 0; if the * user wishes us to allocate 0 bytes, that is fine), or a negative number if * there was an error or special parameter (--help, --version, etc). * * This function should be rewritten to use the getopt library. */ double parseargs(int argc, char *argv[], int *stride, int *naughty, int *bastard, int *quiet) { int i, numpower, stridepower, havenum = 0; double numbytes; char *endptr; for (i = 1; i < argc; i++) { /* print help or version, then exit: */ if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-help") == 0 || strcmp(argv[i], "--help") == 0) return HELP; if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "--version") == 0) return VERSION; /* set any of the quiet, naughty, or bastard flags: */ if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "-quiet") == 0 || strcmp(argv[i], "--quiet") == 0) *quiet = 1; if (strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "-naughty") == 0 || strcmp(argv[i], "--naughty") == 0) *naughty = 1; if (strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "-bastard") == 0 || strcmp(argv[i], "--bastard") == 0) *bastard = 1; /* set the stride: */ if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "-stride") == 0 || strcmp(argv[i], "--stride") == 0) { *stride = strtol(argv[++i], &endptr, BASE); if ((stridepower = powertest(endptr)) == BADNUM || *stride < 1) return BADSTRIDE; /* Raise to the nonstandard yet more appropriate "binary power"; */ /* eg, 1k represents 2^10, not 10^3. */ *stride = *stride * pow(1024, stridepower / 3); fprintf(stderr, "stride: %d; endptr: %d\n", *stride, *endptr); continue; } /* set the grab size: */ if (isdigit(argv[i][0])) /* Octal, decimal, or hexadecimal number. */ { if (havenum++) /* We've already had a number. */ return BADARGS; numbytes = strtod(argv[i], &endptr); if ((numpower = powertest(endptr)) == BADNUM) return BADNUM; /* Raise to the nonstandard yet more appropriate "binary power"; */ /* eg, 1k represents 2^10, not 10^3. */ numbytes = numbytes * pow(1024, numpower / 3); continue; } } if (havenum) return numbytes; else return BADARGS; } /* Return the power to which a number should be raised, defined by the value of * the letter in endptr (eg 'k', 'M', etc). Note that this is case-sensitive * -- after all, 'K' means "Kelvin", not "kilo", 'm' means "milli", not "mega", * and so on -- and for this same reason only positive powers have been * included. I do not want to have to deal with people filing bug reports * complaining about how "grabmem -b 256m DOESNT WORK, D00D!". */ int powertest(char *endptr) { int i; int power[2][8] = { { 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' }, { 3, 6, 9, 12, 15, 18, 21, 24 } }; if (*endptr == '\0') /* No postfix power modifier. */ return 0; for (i = 0; i < 8; i++) if (*endptr == power[0][i]) return power[1][i]; return BADNUM; /* Fall through if no matching power was found. */ } int allocate(char **memptr, double numbytes, int quiet) { if (!quiet) fprintf(stderr, "grabmem: allocating %.0f bytes.\n", numbytes); *memptr = (char *) malloc(numbytes); if (*memptr == NULL) /* Some compilers will not return a pointer to a 0-byte block of memory, */ /* preferring instead to return a NULL pointer; the next statement tests */ /* for this special case: */ if (numbytes > 0) return BADALLOC; return 0; } int initialise(char **memptr, double numbytes, int stride, int bastard) { char *ptr, *endptr; /* It is assumed that on a system using 64-bit pointers, integers of type * "long long" will likewise be 64-bit. */ endptr = *memptr + (long long) numbytes; if (stride < 1) if ((stride = getpagesize()) < 1) stride = 1; do { ptr = *memptr; while (ptr < endptr) { *ptr = FILLBYTE; ptr += stride; } } while (bastard); /* Bastard mode: keep accessing all allocated memory until killed. For a * normal LRU caching algorithm and a grabsize just small enough to avoid * excessive swapping, this will cause every other user-land program to be * swapped out. Yes, this is a DoS attack, and if you run it on a public * machine, the sysadmin's own built-in "bastard mode" will be activated, * and he will cause an even greater level of discomfort to you :-) . */ return 0; } int deallocate(char **memptr, int naughty) { if (!naughty) free(*memptr); else pause(); /* Naughty mode: wait without freeing memory until killed. */ return 0; }