summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile21
-rw-r--r--empty.c56
-rw-r--r--machometer.h21
-rw-r--r--main.c275
-rw-r--r--message.h29
5 files changed, 402 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..41e1c1e
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,21 @@
+# 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.
+
+CFLAGS ?= -W -Wall -O3 -g -std=gnu99
+LDFLAGS ?= -lpthread -lshouldbeinlibc
+
+all: machometer
+
+machometer: main.o empty.o
+ $(CC) $(LDFLAGS) $^ -o $@
diff --git a/empty.c b/empty.c
new file mode 100644
index 0000000..3adc8fa
--- /dev/null
+++ b/empty.c
@@ -0,0 +1,56 @@
+/*
+ * 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 <hurd.h>
+#include <error.h>
+#include <mach.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static mach_msg_header_t send_buffer = {
+ .msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MAKE_SEND),
+};
+
+error_t
+send_empty (mach_port_t server)
+{
+ send_buffer.msgh_remote_port = server;
+
+ return mach_msg (&send_buffer,
+ MACH_SEND_MSG|MACH_MSG_OPTION_NONE,
+ sizeof (send_buffer),
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+}
+
+static mach_msg_header_t receive_buffer = {
+ .msgh_size = sizeof (receive_buffer),
+};
+
+error_t
+receive_empty (mach_port_t port)
+{
+ return mach_msg (&receive_buffer,
+ MACH_RCV_MSG|MACH_MSG_OPTION_NONE,
+ 0,
+ sizeof (receive_buffer),
+ port,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+}
diff --git a/machometer.h b/machometer.h
new file mode 100644
index 0000000..58291de
--- /dev/null
+++ b/machometer.h
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+#include <mach.h>
+
+error_t send_empty (mach_port_t server);
+
+error_t receive_empty (mach_port_t server);
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;
+}
diff --git a/message.h b/message.h
new file mode 100644
index 0000000..8cadda6
--- /dev/null
+++ b/message.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+typedef struct {
+ mach_msg_header_t Head;
+ mach_msg_type_t nType;
+ int n;
+} Request;
+
+typedef struct {
+ mach_msg_header_t Head;
+ mach_msg_type_t RetCodeType;
+ kern_return_t RetCode;
+ mach_msg_type_t nType;
+ int n;
+} Reply;