From 58dedd2cc54d59875b114d4edcadd6bd589ff37c Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Fri, 19 Dec 2014 10:13:09 +0100 Subject: Initial checkin. --- main.c | 275 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 main.c (limited to 'main.c') 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} -- cgit v1.2.3