summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2015-08-24 20:55:29 +0200
committerJustus Winter <4winter@informatik.uni-hamburg.de>2016-02-13 15:04:07 +0100
commit028dfd979c1098f213d3bf9f0fc039ec55da2483 (patch)
tree2901bf713e93ebc374776a3747166f20b05d2746 /utils
parent23f66dec527cea00bd5613c6d52d22a50b54f3d0 (diff)
utils/vmallocate: new utility
* utils/Makefile (targets): Add 'vmallocate'. * utils/vmallocate.c: New file.
Diffstat (limited to 'utils')
-rw-r--r--utils/Makefile2
-rw-r--r--utils/vmallocate.c272
2 files changed, 273 insertions, 1 deletions
diff --git a/utils/Makefile b/utils/Makefile
index 603b7221..d2ef9e86 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -22,7 +22,7 @@ targets = shd ps settrans showtrans syncfs fsysopts \
storeinfo login w uptime ids loginpr sush vmstat portinfo \
devprobe vminfo addauth rmauth unsu setauth ftpcp ftpdir storecat \
storeread msgport rpctrace mount gcore fakeauth fakeroot remap \
- umount nullauth rpcscan
+ umount nullauth rpcscan vmallocate
special-targets = loginpr sush uptime fakeroot remap
SRCS = shd.c ps.c settrans.c syncfs.c showtrans.c addauth.c rmauth.c \
diff --git a/utils/vmallocate.c b/utils/vmallocate.c
new file mode 100644
index 00000000..628cfd12
--- /dev/null
+++ b/utils/vmallocate.c
@@ -0,0 +1,272 @@
+/* vmallocate -- a utility to allocate memory.
+
+ Copyright (C) 2015,2016 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <argp.h>
+#include <assert.h>
+#include <error.h>
+#include <hurd.h>
+#include <inttypes.h>
+#include <mach.h>
+#include <mach/vm_param.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <version.h>
+
+
+
+const char *argp_program_version = STANDARD_HURD_VERSION (vmallocate);
+
+int verbose;
+int do_pause;
+int do_read;
+int do_write;
+
+uint64_t size;
+uint64_t chunk_size = 1U << 30; /* 1 gigabyte */
+uint64_t allocated;
+
+static const struct argp_option options[] =
+{
+ {NULL, 0, NULL, OPTION_DOC, "Mapping options", 1},
+ {"read", 'r', NULL, 0, "read from mapping", 1},
+ {"write", 'w', NULL, 0, "write to mapping", 1},
+
+ {NULL, 0, NULL, OPTION_DOC, "Options", 2},
+ {"verbose", 'v', NULL, 0, "be more verbose", 2},
+ {"pause", 'p', NULL, 0, "read newline from stdin before exiting", 2},
+ {0}
+};
+
+#define UNITS "gGmMkKpP"
+static const char args_doc[] = "SIZE["UNITS"]";
+static const char doc[] = "Allocates memory.\v"
+ "This is a stress-test for the vm system.";
+
+/* Parse our options... */
+error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ char *end;
+ switch (key)
+ {
+ case 'r':
+ do_read = 1;
+ break;
+
+ case 'w':
+ do_write = 1;
+ break;
+
+ case 'v':
+ verbose += 1;
+ break;
+
+ case 'p':
+ do_pause = 1;
+ break;
+
+ case ARGP_KEY_ARG:
+ if (size > 0)
+ argp_error (state, "Extra argument after size: %s", arg);
+
+ size = strtoull (arg, &end, 10);
+ if (arg == end || (end[0] != 0 && end[1] != 0))
+ argp_error (state, "Could not parse size `%s'.", arg);
+
+ switch (end[0]) {
+ case 0:
+ break;
+
+ case 'g':
+ case 'G':
+ size <<= 30;
+ break;
+
+ case 'm':
+ case 'M':
+ size <<= 20;
+ break;
+
+ case 'k':
+ case 'K':
+ size <<= 10;
+ break;
+
+ case 'p':
+ case 'P':
+ size <<= PAGE_SHIFT;
+ break;
+
+ default:
+ argp_error (state,
+ "Unknown unit `%c', expected one of "UNITS".",
+ end[0]);
+ }
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ argp_usage (state);
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+const struct argp argp =
+ {
+ options: options,
+ parser: parse_opt,
+ args_doc: args_doc,
+ doc: doc,
+ };
+
+
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+struct child
+{
+ task_t task;
+ struct child *next;
+};
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ int nchildren = 0;
+ struct child *c, *children = NULL;
+ process_t proc = getproc ();
+
+ /* We must make sure that chunk_size fits into vm_size_t. */
+ assert (chunk_size <= 1U << (sizeof (vm_size_t) * 8 - 1));
+
+ /* Parse our arguments. */
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ if (verbose)
+ fprintf (stderr, "About to allocate %"PRIu64" bytes in chunks of "
+ "%"PRIu64" bytes.\n", size, chunk_size);
+
+ while (allocated < size)
+ {
+ task_t task;
+ uint64_t s = min (chunk_size, size - allocated);
+ vm_address_t address = 0;
+ volatile char *p;
+ char **argv = NULL;
+
+ err = vm_allocate (mach_task_self (), &address, (vm_size_t) s,
+ 1 /* anywhere */);
+ if (err)
+ error (1, err, "vm_allocate");
+
+ /* Write an argument and environment vector. */
+ if (s > 128)
+ {
+ int written;
+ char *arg0;
+
+ arg0 = (char *) address;
+ written = sprintf (arg0, "[vmallocate %d]", nchildren);
+
+ argv = (char **) (address + (unsigned) written + 1);
+ argv[0] = arg0;
+ argv[1] = NULL;
+ }
+
+ for (p = (char *) address + PAGE_SIZE;
+ p < (char *) (address + (size_t) s);
+ p += PAGE_SIZE)
+ {
+ if (do_read)
+ (void) *p;
+ if (do_write)
+ *p = 1;
+
+ if (verbose > 1
+ && ((unsigned int) (p - address) & ((1U<<20) - 1)) == 0)
+ fprintf (stderr, "\r%"PRIu64,
+ allocated
+ + ((uint64_t) (uintptr_t) p - (uint64_t) address));
+ }
+
+ err = vm_inherit (mach_task_self (), address, (vm_size_t) s,
+ VM_INHERIT_COPY);
+ if (err)
+ error (1, err, "vm_inherit");
+
+ err = task_create (mach_task_self (), 1, &task);
+ if (err)
+ error (1, err, "task_create");
+
+ err = proc_child (proc, task);
+ if (err)
+ error (1, err, "proc_child");
+
+ if (argv != NULL)
+ {
+ process_t childp;
+
+ err = proc_task2proc (proc, task, &childp);
+ if (err)
+ error (1, err, "proc_task2proc");
+
+ err = proc_set_arg_locations (childp,
+ (vm_offset_t) &argv[0],
+ (vm_offset_t) &argv[1]);
+ if (err)
+ error (1, err, "proc_set_arg_locations");
+ }
+
+ c = malloc (sizeof *c);
+ if (c == NULL)
+ error (1, errno, "malloc");
+ c->task = task;
+ c->next = children;
+ children = c;
+
+ err = vm_deallocate (mach_task_self (), address, (vm_size_t) s);
+ if (err)
+ error (1, err, "vm_deallocate");
+
+ allocated += s;
+ nchildren += 1;
+
+ if (verbose)
+ fprintf (stderr, "\rAllocated %"PRIu64" bytes.\n", allocated);
+ }
+
+ if (do_pause)
+ {
+ fprintf (stderr, "Press enter to exit and release the memory.");
+ getchar ();
+ }
+
+ for (c = children; c; c = c->next)
+ task_terminate (c->task);
+
+ return EXIT_SUCCESS;
+}