summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2014-12-19 10:13:09 +0100
committerJustus Winter <4winter@informatik.uni-hamburg.de>2014-12-19 15:31:03 +0100
commit58dedd2cc54d59875b114d4edcadd6bd589ff37c (patch)
treec3da9ccc20a6655bd82644b32e00e14552f384df /main.c
Initial checkin.
Diffstat (limited to 'main.c')
-rw-r--r--main.c275
1 files changed, 275 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..4c3b135
--- /dev/null
+++ b/main.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2014 Justus Winter <4winter@informatik.uni-hamburg.de>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define _GNU_SOURCE
+#include <argp.h>
+#include <error.h>
+#include <hurd.h>
+#include <mach.h>
+#include <maptime.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include "machometer.h"
+
+volatile struct mapped_time_value *mtime;
+
+struct producer_args
+{
+ mach_port_t port;
+ size_t count;
+ struct timeval runtime;
+};
+
+void *
+producer (void *args_)
+{
+ error_t err = 0;
+ struct producer_args *args = args_;
+
+ struct timeval start_time;
+ maptime_read (mtime, &start_time);
+
+ for (size_t i = 0; i < args->count; i++)
+ {
+ err = send_empty (args->port);
+ if (err)
+ goto out;
+ }
+
+ struct timeval end_time;
+ maptime_read (mtime, &end_time);
+ timersub (&end_time, &start_time, &args->runtime);
+
+ out:
+ return (void *) err;
+}
+
+struct consumer_args
+{
+ mach_port_t port;
+ size_t count;
+ struct timeval runtime;
+};
+
+error_t
+consumer (void *args_)
+{
+ error_t err;
+ struct consumer_args *args = args_;
+
+ struct timeval start_time;
+ maptime_read (mtime, &start_time);
+
+ for (size_t i = 0; i < args->count; i++)
+ {
+ err = receive_empty (args->port);
+ if (err)
+ return err;
+ }
+
+ struct timeval end_time;
+ maptime_read (mtime, &end_time);
+
+ timersub (&end_time, &start_time, &args->runtime);
+
+ out:
+ return 0;
+}
+
+void
+print_stats (const char *id, size_t n, struct timeval *tv)
+{
+ double duration = tv->tv_sec + (tv->tv_usec / 1000000.);
+ printf ("% 10s: % 3is%06ius\t%fns\t%9.3f (1/s)\n",
+ id,
+ (int) tv->tv_sec, (int) tv->tv_usec,
+ 1000000000. * duration / n,
+ n / duration);
+}
+
+/* Options. */
+mach_port_msgcount_t qlimit = MACH_PORT_QLIMIT_DEFAULT;
+size_t iterations = 1l<<25;
+
+const char *argp_program_version = "machometer-0.0";
+
+static const struct argp_option options[] =
+{
+ {"iterations", 'n', "N", 0, "Repeat tests N times"},
+ {"qlimit", 'Q', "LIMIT", NULL, "Set qlimit"},
+ {NULL}
+};
+
+/* Parse a command line option. */
+error_t parse_opt (int key, char *arg, struct argp_state *state)
+{
+ char *arg_end;
+ unsigned long *ptr = NULL;
+ switch (key)
+ {
+ case 'n':
+ ptr = ptr ?: &iterations;
+ case 'Q':
+ ptr = ptr ?: &qlimit;
+
+ *ptr = strtoul (arg, &arg_end, 10);
+ if (*arg == '\0' || *arg_end != '\0')
+ argp_error (state, "invalid integer: %s", arg);
+ break;
+
+ case ARGP_KEY_ARG:
+ argp_usage (state);
+ return EINVAL;
+
+ case ARGP_KEY_NO_ARGS:
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static struct argp argp =
+ {
+ options,
+ parse_opt,
+ "YYY",
+ "XXX",
+ };
+
+/* mach_print performance test. */
+
+void mach_print(const char *);
+
+#ifndef EXTERNAL_MACH_PRINT
+asm (".global mach_print;"
+ " mach_print:;"
+ " mov $0xffffffe2, %eax;"
+ " lcall $0x7, $0x0;"
+ " ret;");
+#endif /* EXTERNAL_MACH_PRINT */
+
+error_t
+test_mach_print (const size_t n)
+{
+ error_t err = 0;
+ struct timeval start_time;
+ maptime_read (mtime, &start_time);
+
+ for (size_t i = 0; i < n; i++)
+ mach_print ("");
+
+ struct timeval end_time;
+ maptime_read (mtime, &end_time);
+
+ struct timeval runtime;
+ timersub (&end_time, &start_time, &runtime);
+ print_stats ("mach_print", n, &runtime);
+
+ return err;
+}
+
+/* Measure the trap overhead of mach_msg. */
+error_t
+test_null_msg (const size_t n)
+{
+ error_t err = 0;
+ struct timeval start_time;
+ maptime_read (mtime, &start_time);
+
+ for (size_t i = 0; i < n; i++)
+ {
+ err = mach_msg (NULL, MACH_MSG_OPTION_NONE, 0, 0,
+ MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ if (err)
+ goto out;
+ }
+
+ struct timeval end_time;
+ maptime_read (mtime, &end_time);
+
+ struct timeval runtime;
+ timersub (&end_time, &start_time, &runtime);
+ print_stats ("nullmsg", n, &runtime);
+
+ out:
+ return err;
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t port;
+
+ /* Parse our arguments. */
+ argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0);
+
+ fprintf (stderr, "N: %u (1<<%d), qlimit: %d\n",
+ iterations, __builtin_ffs (iterations) - 1, qlimit);
+
+ err = maptime_map (0, NULL, &mtime);
+ if (err)
+ error (1, err, "maptime_map");
+
+ err = test_mach_print (iterations);
+ if (err)
+ error (1, err, "test_mach_print");
+
+ err = test_null_msg (iterations);
+ if (err)
+ error (1, err, "test_null_msg");
+
+ err = mach_port_allocate (mach_task_self(),
+ MACH_PORT_RIGHT_RECEIVE,
+ &port);
+ if (err)
+ error (1, err, "mach_port_allocate");
+
+ err = mach_port_set_qlimit (mach_task_self(),
+ port,
+ qlimit);
+ if (err)
+ error (1, err, "mach_port_set_qlimit");
+
+ struct producer_args pargs = { .port=port, .count=iterations };
+
+ pthread_t producer_thread;
+ err = pthread_create (&producer_thread, NULL, &producer, &pargs);
+ if (err)
+ error (2, err, "pthread_create");
+
+ struct consumer_args cargs = { .port=port, .count=iterations };
+
+ err = consumer (&cargs);
+
+ error_t producer_err;
+ err = pthread_join (producer_thread, (void **)&producer_err);
+ if (err)
+ error (3, err, "pthread_join");
+
+ if (producer_err)
+ error (4, producer_err, "producer");
+
+ print_stats ("producer", iterations, &pargs.runtime);
+ print_stats ("consumer", iterations, &cargs.runtime);
+
+ return EXIT_SUCCESS;
+}