├── .gitignore ├── .gitmodules ├── LICENSE ├── Makefile ├── README.md ├── config.mak ├── tests ├── 01-compiler.c ├── 02-sleep.c ├── 03-pthreads.c ├── 04-lthread-sleep.c ├── 10-lkl-host-print.c ├── 11-lkl-host-panic.c ├── 12-lkl-host-mem.c ├── 13-lkl-host-thread.c ├── 14-lkl-host-tls.c ├── 15-lkl-host-mutex.c ├── 16-lkl-host-semaphore.c ├── 17-lkl-host-time.c ├── 18-lkl-host-timer.c ├── 19-lkl-boot.c ├── 20-lkl-disk.c ├── 20-lkl-disk.tar.gz ├── 21-lkl-net.c ├── 60-iozone │ ├── Changes.txt │ ├── Generate_Graphs │ ├── Gnuplot.txt │ ├── client_list │ ├── fileop.c │ ├── gengnuplot.sh │ ├── gnu3d.dem │ ├── gnuplot.dem │ ├── gnuplotps.dem │ ├── iozone.c │ ├── iozone_visualizer.pl │ ├── libasync.c │ ├── libbif.c │ ├── makefile │ ├── pit_server.c │ ├── read_telemetry │ ├── report.pl │ ├── spec.in │ └── write_telemetry ├── 70-nginx.img ├── 80-memcached.img └── Makefile └── tools ├── bench ├── __init__.py ├── benchmark.py └── utils.py ├── bench_encryption.py ├── bench_iozone_recordsize.py ├── bench_memcached_throughput_latency.py ├── bench_memcached_vanillaVSlkl.py ├── disk_encrypt.c ├── lkl_bits.c └── lkl_syscalls.c /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | results/ 3 | *.pyc 4 | tests/60-iozone/*.o 5 | tests/60-iozone/iozone 6 | *.csv 7 | *.json 8 | *.img 9 | *.tmp 10 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "sgx-musl"] 2 | path = sgx-musl 3 | url = git@sereca.cloudandheat.com:matthieu.buffet/muslkl-sgx.git 4 | [submodule "lkl"] 5 | path = lkl 6 | url = https://github.com/lkl/linux.git 7 | [submodule "host-musl"] 8 | path = host-musl 9 | url = git://git.musl-libc.org/musl 10 | [submodule "libevent"] 11 | path = tests/80-memcached/libevent 12 | url = https://github.com/libevent/libevent.git 13 | [submodule "memcached"] 14 | path = tests/80-memcached/memcached 15 | url = https://github.com/memcached/memcached.git 16 | [submodule "nginx"] 17 | path = tests/70-nginx 18 | url = https://github.com/nginx/nginx.git 19 | [submodule "openssl"] 20 | path = openssl 21 | url = https://github.com/openssl/openssl.git 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Matthieu Buffet 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include config.mak 2 | 3 | .PHONY: host-musl lkl openssl sgx-musl tests tools clean 4 | 5 | default: all 6 | # Default is to build everything and run a basic test suite 7 | all: sgx-musl tests 8 | 9 | tests: sgx-musl tools 10 | +${MAKE} -C ${TESTS} 11 | 12 | # Vanilla Musl compiler 13 | host-musl ${HOST_MUSL_CC}: | ${HOST_MUSL}/.git ${HOST_MUSL_BUILD} 14 | cd ${HOST_MUSL}; [ -f config.mak ] || CFLAGS="$(MUSL_CFLAGS)" ./configure \ 15 | $(MUSL_CONFIGURE_OPTS) \ 16 | --prefix=${HOST_MUSL_BUILD} \ 17 | --disable-shared 18 | +${MAKE} -C ${HOST_MUSL} CFLAGS="$(MUSL_CFLAGS)" install 19 | ln -fs ${LINUX_HEADERS_INC}/linux/ ${HOST_MUSL_BUILD}/include/ 20 | ln -fs ${LINUX_HEADERS_INC}/asm/ ${HOST_MUSL_BUILD}/include/ 21 | ln -fs ${LINUX_HEADERS_INC}/asm-generic/ ${HOST_MUSL_BUILD}/include/ 22 | 23 | # LKL's static library and include/ header directory 24 | lkl ${LIBLKL}: ${HOST_MUSL_CC} | ${LKL}/.git ${LKL_BUILD} 25 | +DESTDIR=${LKL_BUILD} ${MAKE} -C ${LKL}/tools/lkl CC=${HOST_MUSL_CC} PREFIX="" \ 26 | ALL_LIBRARIES=liblkl.a libraries_install 27 | +DESTDIR=${LKL_BUILD} ${MAKE} -C ${LKL}/tools/lkl CC=${HOST_MUSL_CC} PREFIX="" \ 28 | headers_install 29 | #TODO: apply before makes, and to the entire ${LKL} folder? 30 | # Bugfix, prefix symbol that collides with musl's one 31 | find ${LKL_BUILD}/include/ -type f -exec sed -i 's/struct ipc_perm/struct lkl_ipc_perm/' {} \; 32 | +${MAKE} headers_install -C ${LKL} ARCH=lkl INSTALL_HDR_PATH=${LKL_BUILD}/ 33 | 34 | # OpenSSL's static library and include/ header directory 35 | openssl ${LIBCRYPTO}: ${HOST_MUSL_CC} | ${OPENSSL}/.git ${OPENSSL_BUILD} 36 | cd ${OPENSSL}; [ -f Makefile ] || CC=${HOST_MUSL_CC} ./config \ 37 | --prefix=${OPENSSL_BUILD}/ \ 38 | --openssldir=${OPENSSL_BUILD}/openssl/ \ 39 | threads no-zlib no-shared 40 | sed -i 's/^CFLAG=/CFLAG= -fPIC /' ${OPENSSL}/Makefile 41 | +CC=${HOST_MUSL_CC} ${MAKE} -C ${OPENSSL} depend 42 | +CC=${HOST_MUSL_CC} ${MAKE} -C ${OPENSSL} 43 | +CC=${HOST_MUSL_CC} ${MAKE} -C ${OPENSSL} install 44 | 45 | tools: ${TOOLS_OBJ} 46 | 47 | # Generic tool rule (doesn't actually depend on lkl_lib, but on LKL headers) 48 | ${TOOLS_BUILD}/%: ${TOOLS}/%.c ${HOST_MUSL_CC} ${LIBCRYPTO} ${LKL_LIB} | ${TOOLS_BUILD} 49 | ${HOST_MUSL_CC} ${MY_CFLAGS} -I${LKL_BUILD}/include/ -o $@ $< ${MY_LDFLAGS} 50 | 51 | # More headers required by SGX-Musl not exported by LKL, given by a custom tool's output 52 | ${LKL_SGXMUSL_HEADERS}: ${LKL_BUILD}/include/lkl/%.h: ${TOOLS_BUILD}/lkl_% 53 | $< > $@ 54 | 55 | # LKL-SGX-Musl compiler 56 | sgx-musl ${SGX_MUSL_CC}: ${LIBLKL} ${LIBCRYPTO} ${LKL_SGXMUSL_HEADERS} | ${SGX_MUSL_BUILD} 57 | cd ${SGX_MUSL}; [ -f config.mak ] || CFLAGS="$(MUSL_CFLAGS)" ./configure \ 58 | $(MUSL_CONFIGURE_OPTS) \ 59 | --prefix=${SGX_MUSL_BUILD} \ 60 | --lklheaderdir=${LKL_BUILD}/include/ \ 61 | --lkllib=${LIBLKL} \ 62 | --opensslheaderdir=${OPENSSL_BUILD}/include/ \ 63 | --openssllib=${LIBCRYPTO} \ 64 | --disable-shared 65 | +${MAKE} -C ${SGX_MUSL} CFLAGS="$(MUSL_CFLAGS)" install 66 | 67 | # Build directories (one-shot after git clone or clean) 68 | ${BUILD_DIR} ${TOOLS_BUILD} ${LKL_BUILD} ${HOST_MUSL_BUILD} ${SGX_MUSL_BUILD} ${OPENSSL_BUILD}: 69 | @mkdir -p $@ 70 | 71 | # Submodule initialisation (one-shot after git clone) 72 | ${HOST_MUSL}/.git ${LKL}/.git ${OPENSSL}/.git ${SGX_MUSL}/.git: 73 | [ "$(FORCE_SUBMODULES_VERSION)" = "true" ] || git submodule update --init $($@:.git=) 74 | 75 | clean: 76 | rm -rf ${BUILD_DIR} 77 | +${MAKE} -C ${HOST_MUSL} distclean || true 78 | +${MAKE} -C ${SGX_MUSL} distclean || true 79 | +${MAKE} -C ${OPENSSL} clean || true 80 | +${MAKE} -C ${LKL} clean || true 81 | +${MAKE} -C ${LKL}/tools/lkl clean || true 82 | +${MAKE} -C ${TESTS} clean || true 83 | rm -f ${HOST_MUSL}/config.mak 84 | rm -f ${SGX_MUSL}/config.mak 85 | rm -f ${OPENSSL}/Makefile 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # muslkl 2 | 3 | **(Work in progress)** 4 | 5 | A unikernel builder based on Musl and LKL, designed to run any vanilla application inside an SGX enclave. 6 | This project depends mostly on LKL, Musl and a fork of SGX-Musl, which is itself a fork of Musl created by the [SeReCa (Secure Enclaves for REactive Cloud Applications)](http://www.serecaproject.eu) European research project. All these projects are independent and under different licenses. 7 | 8 | ## Building 9 | 10 | To run tests or any networked application, you will need to create a network tap and a bridge (more steps are required if you want your application to be reachable from/reach other hosts). Just run the following commands as root: 11 | 12 | ip link add dev lklbr0 type bridge 13 | ip tuntap add dev tap0 mode tap user 14 | ip link set dev tap0 master lklbr0 up 15 | ip addr add 10.0.1.254/24 dev lklbr0 16 | 17 | If your *ip* command is not up-to-date, you need to use separate *tunctl* and *bridge-utils* packages instead of *ip*: 18 | 19 | tunctl -t tap0 -u 20 | brctl addbr lklbr0 21 | brctl addif lklbr0 tap0 22 | ip addr add 10.0.1.1/24 dev lklbr0 23 | ip link set dev lklbr0 up 24 | 25 | All dependencies are handled as Git submodules, but this project relies partly on a closed-source codebase. Access was kindly given to me to develop this project as part of my MSc thesis. Once you get access to it, building the whole project is as simple as: 26 | 27 | git clone https://github.com/mtth-bfft/muslkl.git 28 | cd muslkl 29 | make 30 | -------------------------------------------------------------------------------- /config.mak: -------------------------------------------------------------------------------- 1 | # Disable verbose output and implicit rules (harder to debug) 2 | #.SUFFIXES: 3 | #MAKEFLAGS += --no-print-directory 4 | 5 | MUSLKLSGX_STD_RUN_OPTS ?= MUSL_ETHREADS=4 MUSL_STHREADS=4 6 | 7 | #TODO: use autoconf or auto detect 8 | LINUX_HEADERS_INC ?= /usr/include 9 | 10 | FORCE_SUBMODULES_VERSION ?= false 11 | 12 | ROOT_DIR ?= $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) 13 | BUILD_DIR ?= $(ROOT_DIR)/build 14 | TESTS ?= $(ROOT_DIR)/tests 15 | TESTS_BUILD ?= $(BUILD_DIR)/tests 16 | TESTS_SRC ?= $(sort $(wildcard $(TESTS)/*.c)) 17 | TESTS_OBJ ?= $(addprefix $(TESTS_BUILD)/, $(notdir $(TESTS_SRC:.c=))) 18 | LIBEVENT ?= ${TESTS}/80-memcached/libevent 19 | LIBEVENT_BUILD ?= ${TESTS_BUILD}/80-memcached/libevent 20 | MEMCACHED ?= ${TESTS}/80-memcached/memcached 21 | MEMCACHED_BUILD ?= ${TESTS_BUILD}/80-memcached/memcached 22 | NGINX ?= ${TESTS}/70-nginx 23 | NGINX_BUILD ?= ${TESTS_BUILD}/70-nginx 24 | IOZONE ?= ${TESTS}/60-iozone 25 | TOOLS ?= ${ROOT_DIR}/tools 26 | TOOLS_BUILD ?= $(BUILD_DIR)/tools 27 | TOOLS_SRC ?= $(wildcard $(TOOLS)/*.c) 28 | TOOLS_OBJ ?= $(addprefix $(TOOLS_BUILD)/, $(notdir $(TOOLS_SRC:.c=))) 29 | OPENSSL ?= ${ROOT_DIR}/openssl 30 | OPENSSL_BUILD ?= ${BUILD_DIR}/openssl 31 | LIBCRYPTO ?= ${OPENSSL_BUILD}/lib/libcrypto.a 32 | LKL ?= $(ROOT_DIR)/lkl 33 | LKL_BUILD ?= ${BUILD_DIR}/lkl 34 | LIBLKL ?= ${LKL_BUILD}/lib/liblkl.a 35 | HOST_MUSL ?= $(ROOT_DIR)/host-musl 36 | HOST_MUSL_BUILD ?= $(BUILD_DIR)/host-musl 37 | HOST_MUSL_CC ?= ${HOST_MUSL_BUILD}/bin/musl-gcc 38 | SGX_MUSL ?= $(ROOT_DIR)/sgx-musl 39 | SGX_MUSL_BUILD ?= ${BUILD_DIR}/sgx-musl 40 | SGX_MUSL_CC ?= ${SGX_MUSL_BUILD}/bin/sgxmusl-gcc 41 | # Headers not exported by LKL and built by a custom tool's output cat to the file instead 42 | LKL_SGXMUSL_HEADERS ?= ${LKL_BUILD}/include/lkl/bits.h ${LKL_BUILD}/include/lkl/syscalls.h 43 | 44 | # sgxmusl-gcc options, just for our test suite and tools 45 | MY_CFLAGS ?= -std=c11 -Wall -Wextra -Werror -isystem ${SGX_MUSL}/src/internal/ -I${OPENSSL_BUILD}/include/ 46 | MY_LDFLAGS ?= -L${OPENSSL_BUILD}/lib -lcrypto 47 | 48 | DEBUG ?= false 49 | 50 | MUSL_CONFIGURE_OPTS ?= 51 | MUSL_CFLAGS ?= -fPIC -D__USE_GNU 52 | NGINX_CONFIGURE_OPTS ?= 53 | 54 | ifeq ($(DEBUG),true) 55 | MUSL_CONFIGURE_OPTS += --disable-optimize --enable-debug 56 | MUSL_CFLAGS += -g -O0 -DDEBUG 57 | NGINX_CONFIGURE_OPTS += --with-debug 58 | MY_CFLAGS += -ggdb3 -O0 59 | else 60 | MY_CFLAGS += -O3 61 | endif 62 | -------------------------------------------------------------------------------- /tests/01-compiler.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 42; 3 | } 4 | -------------------------------------------------------------------------------- /tests/02-sleep.c: -------------------------------------------------------------------------------- 1 | #define _BSD_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define SLEEP_TIME_NS (1*1000*1000*1000UL) 8 | #define USLEEP_TIME_NS (500*1000*1000UL) 9 | #define NSLEEP_TIME_NS 1000*1000UL 10 | // We require at least millisecond precision for LKL timers. 11 | #define SLEEP_DRIFT_TOLERANCE_NS (500*1000UL) 12 | 13 | static unsigned long long timestamp_ns_now() { 14 | struct timespec ts; 15 | int res = clock_gettime(CLOCK_REALTIME, &ts); 16 | if (res != 0) { 17 | fprintf(stderr, "clock_gettime() returned %d\n", res); 18 | perror("clock_gettime()"); 19 | return res; 20 | } 21 | return (ts.tv_sec * (1000*1000*1000UL) + ts.tv_nsec); 22 | } 23 | 24 | int main() { 25 | printf("Going to sleep()...\n"); 26 | unsigned long long ns_start = timestamp_ns_now(); 27 | unsigned int left = sleep(SLEEP_TIME_NS/(1000*1000*1000UL)); 28 | unsigned long long ns_stop = timestamp_ns_now(); 29 | if (left != 0) { 30 | fprintf(stderr, "Error, sleep() interrupted: %ds left\n", left); 31 | return left; 32 | } 33 | if ((ns_stop - ns_start) < (SLEEP_TIME_NS - SLEEP_DRIFT_TOLERANCE_NS) || 34 | ((ns_stop - ns_start) > (SLEEP_TIME_NS + SLEEP_DRIFT_TOLERANCE_NS))) { 35 | fprintf(stderr, "Error: sleep() %llu ns instead of %llu\n", 36 | ns_stop-ns_start, (unsigned long long)SLEEP_TIME_NS); 37 | return 1; 38 | } 39 | 40 | printf("Going to usleep()...\n"); 41 | ns_start = timestamp_ns_now(); 42 | int res = usleep(USLEEP_TIME_NS/(1000UL)); 43 | ns_stop = timestamp_ns_now(); 44 | if (res != 0) { 45 | fprintf(stderr, "Error, usleep() returned %d\n", res); 46 | return res; 47 | } 48 | if ((ns_stop - ns_start) < (USLEEP_TIME_NS - SLEEP_DRIFT_TOLERANCE_NS) || 49 | ((ns_stop - ns_start) > (USLEEP_TIME_NS + SLEEP_DRIFT_TOLERANCE_NS))) { 50 | fprintf(stderr, "Error: usleep() %llu ns instead of %llu\n", 51 | ns_stop-ns_start, (unsigned long long)USLEEP_TIME_NS); 52 | return 1; 53 | } 54 | 55 | printf("Going to nanosleep()...\n"); 56 | ns_start = timestamp_ns_now(); 57 | struct timespec ts; 58 | ts.tv_sec = 0; 59 | ts.tv_nsec = NSLEEP_TIME_NS; 60 | res = nanosleep(&ts, NULL); 61 | ns_stop = timestamp_ns_now(); 62 | if (res != 0) { 63 | fprintf(stderr, "Error, nanosleep() returned %d\n", res); 64 | return res; 65 | } 66 | if ((ns_stop - ns_start) < (NSLEEP_TIME_NS - SLEEP_DRIFT_TOLERANCE_NS) || 67 | ((ns_stop - ns_start) > (NSLEEP_TIME_NS + SLEEP_DRIFT_TOLERANCE_NS))) { 68 | fprintf(stderr, "Error: nanosleep() %llu ns instead of %llu\n", 69 | ns_stop-ns_start, (unsigned long long)NSLEEP_TIME_NS); 70 | return 1; 71 | } 72 | return 0; 73 | } 74 | 75 | -------------------------------------------------------------------------------- /tests/03-pthreads.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #ifndef _GNU_SOURCE 5 | #define _GNU_SOURCE 6 | #endif 7 | #include 8 | 9 | #define ARGVAL ((void*)0xDEADC0DE) 10 | #define RETVAL ((void*)0xBAADC0DE) 11 | #define INVALID_RETVAL ((void*)0xDEADDEAD) 12 | #define UNUSED(x) (void)(x) 13 | 14 | static pthread_t main_thread_tid = 0; 15 | static volatile int busy_wait_join_detached = 0; 16 | static volatile int canceled_but_still_running = 0; 17 | 18 | void check_state(int newstate) { 19 | static int lock = 0; 20 | static int state = 0; 21 | while (__sync_lock_test_and_set(&lock, 1) == 1) { } 22 | if (newstate != state && newstate != (state+1)) { 23 | fprintf(stderr, "State %d reached from state %d\n", 24 | newstate, state); 25 | exit(4); 26 | } 27 | state = newstate; 28 | __sync_lock_release(&lock); 29 | } 30 | 31 | void* secondary_exit(void *arg) { 32 | check_state(2); 33 | if (arg != ARGVAL) { 34 | fprintf(stderr, "Wrong argument %p received in thread\n", arg); 35 | exit(2); 36 | } 37 | 38 | pthread_t tid = pthread_self(); 39 | if (tid == 0 || tid == main_thread_tid) 40 | fprintf(stderr, "WARN: child thread has tid %lld, main has %lld ", 41 | (unsigned long long)tid, 42 | (unsigned long long)main_thread_tid); 43 | 44 | // Cannot use wait()/sleep() operations 45 | volatile int i = 0; 46 | while (i < 10000000L) 47 | i++; 48 | printf("Secondary exit thread alive\n"); 49 | check_state(3); 50 | 51 | pthread_exit(RETVAL); 52 | // Should never be executed, but frankenlibc's POSIX thread emulation 53 | // did let this return... 54 | return INVALID_RETVAL; 55 | } 56 | 57 | void* secondary_return(void *arg) { 58 | UNUSED(arg); 59 | check_state(5); 60 | 61 | // Cannot use wait()/sleep() operations 62 | volatile int i = 0; 63 | while (i < 10000000L) 64 | i++; 65 | printf("Secondary return thread alive\n"); 66 | 67 | check_state(6); 68 | return RETVAL; 69 | } 70 | 71 | void* secondary_detach(void *arg) { 72 | UNUSED(arg); 73 | pthread_t tid = pthread_self(); 74 | if (tid == 0) { 75 | fprintf(stderr, "Error: pthread_self() returned 0\n"); 76 | exit(1); 77 | } 78 | int res = pthread_detach(tid); 79 | if (res != 0) { 80 | fprintf(stderr, "Error: pthread_detach(%lld) returned %d\n", 81 | (unsigned long long)tid, res); 82 | exit(res); 83 | } 84 | 85 | printf("Secondary detached thread alive\n"); 86 | pthread_exit(RETVAL); 87 | // Should never be executed 88 | return INVALID_RETVAL; 89 | } 90 | 91 | void* secondary_cancel(void *arg) { 92 | UNUSED(arg); 93 | usleep(1000*1000); 94 | canceled_but_still_running = 1; 95 | return RETVAL; 96 | } 97 | 98 | int main() { 99 | // Check pthread_self() 100 | main_thread_tid = pthread_self(); 101 | 102 | // Check pthread_create() 103 | check_state(1); 104 | pthread_t thread1; 105 | printf("Creating secondary_exit thread\n"); 106 | int res = pthread_create(&thread1, NULL, &secondary_exit, ARGVAL); 107 | if (res != 0) { 108 | fprintf(stderr, "Error: pthread_create() returned %d\n", res); 109 | return res; 110 | } 111 | printf("Main survived\n"); 112 | 113 | // Check pthread_exit() and pthread_join() 114 | check_state(2); 115 | void *returned = NULL; 116 | res = pthread_join(thread1, &returned); 117 | if (res != 0) { 118 | fprintf(stderr, "Error: pthread_join() returned %d\n", res); 119 | return res; 120 | } 121 | if (returned != RETVAL) 122 | fprintf(stderr, "WARN: wrong pthread_join() return %p ", returned); 123 | check_state(4); 124 | 125 | // Check return from thread secondary function 126 | pthread_t thread2; 127 | res = pthread_create(&thread2, NULL, &secondary_return, ARGVAL); 128 | if (res != 0) { 129 | fprintf(stderr, "Error: pthread_create() returned %d\n", res); 130 | return res; 131 | } 132 | 133 | check_state(5); 134 | returned = NULL; 135 | res = pthread_join(thread2, &returned); 136 | if (res != 0) { 137 | fprintf(stderr, "Error: pthread_join() returned %d\n", res); 138 | return res; 139 | } 140 | check_state(7); 141 | 142 | // Check pthread_detach() 143 | pthread_t thread3; 144 | res = pthread_create(&thread3, NULL, &secondary_detach, ARGVAL); 145 | if (res != 0) { 146 | fprintf(stderr, "Error: pthread_create() returned %d\n", res); 147 | return res; 148 | } 149 | 150 | // Check pthread_cancel() + pthread_join() 151 | pthread_t thread4; 152 | res = pthread_create(&thread4, NULL, &secondary_cancel, ARGVAL); 153 | if (res != 0) { 154 | fprintf(stderr, "Error: pthread_create() returned %d\n", res); 155 | return res; 156 | } 157 | usleep(1000); 158 | res = pthread_cancel(thread4); 159 | if (res != 0) { 160 | fprintf(stderr, "Error: pthread_cancel() returned %d\n", res); 161 | return res; 162 | } 163 | returned = NULL; 164 | res = pthread_join(thread4, &returned); 165 | if (res != 0) { 166 | fprintf(stderr, "Error: pthread_join(canceled) returned %d\n", 167 | res); 168 | return res; 169 | } 170 | if (returned != PTHREAD_CANCELED) 171 | fprintf(stderr, "WARN: returned %p, not PTHREAD_CANCELED ", 172 | returned); 173 | 174 | return 0; 175 | } 176 | 177 | -------------------------------------------------------------------------------- /tests/04-lthread-sleep.c: -------------------------------------------------------------------------------- 1 | #define _POSIX_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define UNUSED(x) (void)(x) 9 | 10 | #define SLEEP_TIME_S 2 11 | #define SLEEP_TIME_MS (1000*SLEEP_TIME_S) 12 | #define SLEEP_TIME_NS ((1000*1000)*SLEEP_TIME_MS) 13 | 14 | // lthread has millisecond accuracy at best 15 | #define SLEEP_DRIFT_ALLOWED_NS (1000*1000) 16 | 17 | volatile int join_barrier_reached = 0; 18 | 19 | // lthread headers are not exported properly for now 20 | void lthread_sleep(uint64_t msecs); 21 | 22 | unsigned long long timestamp_now_ns() { 23 | struct timespec ts; 24 | int res = clock_gettime(CLOCK_REALTIME, &ts); 25 | if (res != 0) { 26 | fprintf(stderr, "clock_gettime() returned %d\n", res); 27 | perror("clock_gettime()"); 28 | return res; 29 | } 30 | return (ts.tv_sec * (1000*1000*1000UL) + ts.tv_nsec); 31 | } 32 | 33 | void check_state(int newstate) { 34 | static int lock = 0; 35 | while (__sync_lock_test_and_set(&lock, 1) == 1) { } 36 | static int state = 0; 37 | if (newstate != state && newstate != (state+1)) { 38 | fprintf(stderr, "State %d reached from state %d\n", 39 | newstate, state); 40 | exit(1); 41 | } 42 | state = newstate; 43 | __sync_lock_release(&lock); 44 | } 45 | 46 | void* secondary_sleep(void* arg) { 47 | UNUSED(arg); 48 | unsigned long long target_ns = SLEEP_TIME_S*1000*1000*1000UL; 49 | unsigned long long start_ns = timestamp_now_ns(); 50 | 51 | check_state(2); 52 | printf("Testing lthread_sleep(%d ms)...\n", SLEEP_TIME_MS); 53 | lthread_sleep(SLEEP_TIME_MS); 54 | check_state(3); 55 | 56 | unsigned long long elapsed_ns = timestamp_now_ns() - start_ns; 57 | long long diff_ns = (long long)elapsed_ns - (long long)target_ns; 58 | printf("Returned from lthread_sleep()\n"); 59 | double drift = (diff_ns*100.0)/target_ns; 60 | if (diff_ns < -SLEEP_DRIFT_ALLOWED_NS || diff_ns > SLEEP_DRIFT_ALLOWED_NS) { 61 | fprintf(stderr, "WARN: lthread_sleep(%lld) drift %lld (%.3f %%) ", 62 | (long long)SLEEP_TIME_S, diff_ns, drift); 63 | } 64 | 65 | join_barrier_reached = 1; 66 | return NULL; 67 | } 68 | 69 | int main() { 70 | check_state(1); 71 | pthread_t thread1; 72 | printf("Creating secondary_sleep thread\n"); 73 | int res = pthread_create(&thread1, NULL, &secondary_sleep, NULL); 74 | if (res != 0) { 75 | fprintf(stderr, "Error: pthread_create() returned %d\n", res); 76 | return res; 77 | } 78 | check_state(2); 79 | printf("Main thread alive, waiting for secondary wakeup\n"); 80 | /*res = pthread_join(thread1, NULL); 81 | if (res != 0) { 82 | fprintf(stderr, "Error: pthread_join() returned %d\n", res); 83 | return res; 84 | }*/ 85 | while (!join_barrier_reached) { 86 | printf("."); 87 | for(volatile int i = 0; i < 100000; i++) { } 88 | lthread_sleep(0); // yield 89 | } 90 | 91 | check_state(4); 92 | return 0; 93 | } 94 | 95 | -------------------------------------------------------------------------------- /tests/10-lkl-host-print.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | lkl_host_ops.print("OK\n", 3); 7 | return 0; 8 | } 9 | 10 | -------------------------------------------------------------------------------- /tests/11-lkl-host-panic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | lkl_host_ops.panic(); 7 | return 0; 8 | } 9 | 10 | -------------------------------------------------------------------------------- /tests/12-lkl-host-mem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Checks that the allocated area is R/W 5 | void check(volatile char* area, unsigned long size) { 6 | unsigned long i; 7 | for(i = 0; i < size; i++) 8 | *(area + i) = (char)i; 9 | } 10 | 11 | int main() { 12 | unsigned long size; 13 | for(size = 10; size <= 1024*1024*10; size *= 10) { 14 | void* test = lkl_host_ops.mem_alloc(size); 15 | if (test == NULL) 16 | return (int)size; 17 | check(test, size); 18 | lkl_host_ops.mem_free(test); 19 | } 20 | return 0; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /tests/13-lkl-host-thread.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define UNUSED(x) (void)(x) 7 | 8 | static long main_thread_tid = 0; 9 | 10 | void check_state(int newstate) { 11 | static int state = 0; 12 | static int lock = 0; 13 | while (__sync_lock_test_and_set(&lock, 1) == 1) { } 14 | if (newstate != state && newstate != (state+1)) { 15 | fprintf(stderr, "State %d reached from state %d\n", 16 | newstate, state); 17 | exit(4); 18 | } 19 | state = newstate; 20 | __sync_lock_release(&lock); 21 | } 22 | 23 | void secondary_exit(void* arg) { 24 | check_state(2); 25 | if (arg != (void*)0xBAADC0DE) { 26 | fprintf(stderr, "Wrong argument received in secondary thread\n"); 27 | exit(2); 28 | } 29 | 30 | long tid = lkl_host_ops.gettid(); 31 | if (tid == 0 || tid == main_thread_tid) 32 | fprintf(stderr, "WARN: child thread has tid %ld, main has %ld ", 33 | tid, main_thread_tid); 34 | 35 | // Cannot use wait()/sleep() operations 36 | volatile int i = 0; 37 | while (i < 10000000L) 38 | i++; 39 | check_state(3); 40 | 41 | lkl_host_ops.thread_exit(); 42 | } 43 | 44 | void secondary_return(void* arg) { 45 | UNUSED(arg); 46 | check_state(5); 47 | 48 | // Cannot use wait()/sleep() operations 49 | volatile int i = 0; 50 | while (i < 10000000L) 51 | i++; 52 | 53 | check_state(6); 54 | return; 55 | } 56 | 57 | void secondary_detach(void* arg) { 58 | UNUSED(arg); 59 | lkl_host_ops.thread_detach(); 60 | lkl_host_ops.thread_exit(); 61 | } 62 | 63 | int main() { 64 | // Check gettid 65 | main_thread_tid = lkl_host_ops.gettid(); 66 | 67 | // Check thread_create 68 | check_state(1); 69 | lkl_thread_t thread = lkl_host_ops.thread_create(&secondary_exit, 70 | (void*)0xBAADC0DE); 71 | if (thread == 0) { 72 | fprintf(stderr, "Failed to create thread, returned 0\n"); 73 | return 1; 74 | } 75 | 76 | // Check thread_exit and thread_join 77 | check_state(2); 78 | int res = lkl_host_ops.thread_join(thread); 79 | if (res != 0) { 80 | fprintf(stderr, "Failed to join thread, returned %d\n", res); 81 | return res; 82 | } 83 | check_state(4); 84 | 85 | // Check return from thread secondary function 86 | thread = lkl_host_ops.thread_create(&secondary_return, 87 | (void*)0xBAADC0DE); 88 | if (thread == 0) { 89 | fprintf(stderr, "Failed to create thread, returned 0\n"); 90 | return 1; 91 | } 92 | 93 | check_state(5); 94 | res = lkl_host_ops.thread_join(thread); 95 | if (res != 0) { 96 | fprintf(stderr, "Failed to join thread, returned %d\n", res); 97 | return res; 98 | } 99 | check_state(7); 100 | 101 | // Check thread_detach 102 | thread = lkl_host_ops.thread_create(&secondary_detach, 103 | (void*)0xBAADC0DE); 104 | if (thread == 0) { 105 | fprintf(stderr, "Failed to create thread, returned 0\n"); 106 | return 1; 107 | } 108 | 109 | return 0; 110 | } 111 | 112 | -------------------------------------------------------------------------------- /tests/14-lkl-host-tls.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define UNUSED(x) (void)(x) 7 | 8 | #define VAL1_1 ((void*)0xCAFE0011) 9 | #define VAL2_1 ((void*)0xCAFE0021) 10 | #define VAL1_2 ((void*)0xCAFE0012) 11 | #define VAL2_2 ((void*)0xCAFE0022) 12 | 13 | static unsigned int key1 = 0; 14 | static unsigned int key2 = 0; 15 | 16 | volatile int join_busy_wait = 0; 17 | 18 | void secondary(void* arg) { 19 | UNUSED(arg); 20 | int res = lkl_host_ops.tls_set(key1, VAL1_2); 21 | if (res != 0) { 22 | fprintf(stderr, "Failed tls_set() in secondary thread, " 23 | "code %d\n", res); 24 | exit(res); 25 | } 26 | arg = lkl_host_ops.tls_get(key1); 27 | if (arg != VAL1_2) { 28 | fprintf(stderr, "Incorrect tls_get in secondary thread: %p\n", 29 | arg); 30 | exit(8); 31 | } 32 | join_busy_wait = 1; 33 | } 34 | 35 | int main() { 36 | // Check TLS alloc 37 | int res = lkl_host_ops.tls_alloc(&key1); 38 | if (res != 0) { 39 | fprintf(stderr, "Failed first tls_alloc, returned %d\n", res); 40 | return res; 41 | } 42 | res = lkl_host_ops.tls_alloc(&key2); 43 | if (res != 0) { 44 | fprintf(stderr, "Failed second tls_alloc, returned %d\n", res); 45 | return res; 46 | } 47 | if (key1 == key2) { 48 | fprintf(stderr, "WARN: broken tls_alloc(), only 1 key %u ", key1); 49 | return 1; 50 | } 51 | 52 | // Check tls_set and tls_get in the same thread 53 | res = lkl_host_ops.tls_set(key1, VAL1_1); 54 | if (res != 0) { 55 | fprintf(stderr, "First tls_set failed, returned %d\n", res); 56 | return res; 57 | } 58 | void *val = lkl_host_ops.tls_get(key1); 59 | if (val != VAL1_1) { 60 | fprintf(stderr, "Incorrect first tls_get result: %p\n", val); 61 | return 2; 62 | } 63 | // (frankenlibc's pseudo-TLS failed to maintain two variables at 64 | // the same time) 65 | res = lkl_host_ops.tls_set(key2, VAL2_1); 66 | if (res != 0) { 67 | fprintf(stderr, "Second tls_set failed, returned %d\n", res); 68 | return res; 69 | } 70 | val = lkl_host_ops.tls_get(key2); 71 | if (val != VAL2_1) { 72 | fprintf(stderr, "Incorrect second tls_get result: %p\n", val); 73 | return 3; 74 | } 75 | 76 | // Check tls_get/set in multiple threads 77 | lkl_thread_t thread = lkl_host_ops.thread_create(&secondary, NULL); 78 | if (thread == 0) { 79 | fprintf(stderr, "Failed to thread_create\n"); 80 | return 4; 81 | } 82 | 83 | while (join_busy_wait == 0) { 84 | volatile int i = 0; 85 | for (i = 0; i < 1000000; i++) { } 86 | // We have to keep emitting syscalls while busy waiting 87 | // to avoid starving the secondary thread (userland scheduling...) 88 | printf("."); 89 | } 90 | 91 | val = lkl_host_ops.tls_get(key1); 92 | if (val != VAL1_1) { 93 | fprintf(stderr, "TLS value modified by another thread\n"); 94 | return 5; 95 | } 96 | 97 | // Check tls_free 98 | res = lkl_host_ops.tls_free(key1); 99 | if (res != 0) { 100 | fprintf(stderr, "First tls_free failed, returned %d\n", res); 101 | return res; 102 | } 103 | res = lkl_host_ops.tls_free(key2); 104 | if (res != 0) { 105 | fprintf(stderr, "Second tls_free failed, returned %d\n", res); 106 | return res; 107 | } 108 | 109 | return 0; 110 | } 111 | 112 | -------------------------------------------------------------------------------- /tests/15-lkl-host-mutex.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define UNUSED(x) (void)(x) 6 | 7 | static struct lkl_mutex* mut = NULL; 8 | 9 | void secondary(void* arg) { 10 | UNUSED(arg); 11 | // Cannot use wait()/sleep() operations 12 | volatile int i = 0; 13 | while (i < 10000000L) 14 | i++; 15 | lkl_host_ops.mutex_unlock(mut); 16 | } 17 | 18 | int main() { 19 | // Check mutex_alloc 20 | mut = lkl_host_ops.mutex_alloc(); 21 | if (mut == NULL) { 22 | fprintf(stderr, "Failed to mutex_alloc\n"); 23 | return 1; 24 | } 25 | 26 | // Check non-blocking mutex_lock 27 | lkl_host_ops.mutex_lock(mut); 28 | 29 | // Check blocking mutex_lock and ordering 30 | lkl_thread_t thread = lkl_host_ops.thread_create(&secondary, NULL); 31 | if (thread == 0) { 32 | fprintf(stderr, "Failed to thread_create\n"); 33 | return 2; 34 | } 35 | 36 | lkl_host_ops.mutex_lock(mut); 37 | 38 | // Check mutex_free 39 | lkl_host_ops.mutex_free(mut); 40 | 41 | return 0; 42 | } 43 | 44 | -------------------------------------------------------------------------------- /tests/16-lkl-host-semaphore.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define UNUSED(x) (void)(x) 5 | 6 | static struct lkl_sem* sem1 = NULL; 7 | static struct lkl_sem* sem2 = NULL; 8 | 9 | void secondary(void* arg) { 10 | UNUSED(arg); 11 | lkl_host_ops.sem_up(sem1); 12 | lkl_host_ops.sem_down(sem2); 13 | lkl_host_ops.thread_exit(); 14 | } 15 | 16 | int main() { 17 | // Check sem_alloc 18 | sem1 = lkl_host_ops.sem_alloc(0); 19 | sem2 = lkl_host_ops.sem_alloc(0); 20 | if (sem1 == NULL || sem2 == NULL) 21 | return 1; 22 | 23 | // Check sem_up and non-blocking sem_down 24 | lkl_host_ops.sem_up(sem1); 25 | lkl_host_ops.sem_up(sem1); 26 | lkl_host_ops.sem_down(sem1); 27 | lkl_host_ops.sem_down(sem1); 28 | 29 | // Check blocking sem_down and ordering 30 | lkl_thread_t thread = lkl_host_ops.thread_create(&secondary, NULL); 31 | if (thread == 0) 32 | return -1; 33 | 34 | lkl_host_ops.sem_up(sem2); 35 | lkl_host_ops.sem_down(sem1); 36 | 37 | lkl_host_ops.sem_free(sem1); 38 | lkl_host_ops.sem_free(sem2); 39 | 40 | return 0; 41 | } 42 | 43 | -------------------------------------------------------------------------------- /tests/17-lkl-host-time.c: -------------------------------------------------------------------------------- 1 | #define _POSIX_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define ALLOWED_CLOCK_DELTA_NS (1000*1000UL) 10 | #define TEST_DURATION_NS (1000*1000*1000*2UL) 11 | 12 | static unsigned long long timestamp_ns_now() { 13 | struct timespec ts; 14 | int res = clock_gettime(CLOCK_REALTIME, &ts); 15 | if (res != 0) { 16 | fprintf(stderr, "clock_gettime() returned %d\n", res); 17 | perror("clock_gettime()"); 18 | return res; 19 | } 20 | return (ts.tv_sec * (1000*1000*1000UL) + ts.tv_nsec); 21 | } 22 | 23 | static void format_ns_time(unsigned long long timestamp_ns, char* buf, size_t len) { 24 | time_t secs_part = (time_t)(timestamp_ns / (1000*1000*1000)); 25 | unsigned long ns_part = timestamp_ns % (1000*1000*1000); 26 | struct tm *time = gmtime((time_t*)&secs_part); 27 | strftime(buf, len, "%d/%m/%Y %H:%M:%S", time); 28 | snprintf(buf+strlen(buf), len-strlen(buf), ".%09ld", ns_part); 29 | } 30 | 31 | int main() { 32 | // Check time() compared to host datetime 33 | unsigned long long real_t = timestamp_ns_now(); 34 | unsigned long long t = lkl_host_ops.time(); 35 | char real_t_buf[30] = {0}; 36 | char t_buf[30] = {0}; 37 | format_ns_time(real_t, real_t_buf, sizeof(real_t_buf)); 38 | format_ns_time(t, t_buf, sizeof(t_buf)); 39 | 40 | if (t < (real_t - ALLOWED_CLOCK_DELTA_NS)) 41 | fprintf(stderr, "WARN: in past (real=%s? / guest=%s)) ", 42 | real_t_buf, t_buf); 43 | else if(t > (real_t + ALLOWED_CLOCK_DELTA_NS)) 44 | fprintf(stderr, "WARN: in future (real=%s? / guest=%s) ", 45 | real_t_buf, t_buf); 46 | 47 | // Check that time() is monotonic and actually increases 48 | unsigned long long ns_elapsed = 0; 49 | unsigned long long previous_timestamp = lkl_host_ops.time(); 50 | int warn = 0; 51 | while (ns_elapsed < TEST_DURATION_NS) { 52 | long long delta = lkl_host_ops.time() - previous_timestamp; 53 | if (delta < 0 && !warn) { 54 | fprintf(stderr, "WARN: clock went backwards %lldns", delta); 55 | warn = 1; 56 | } 57 | ns_elapsed += delta; 58 | } 59 | 60 | return 0; 61 | } 62 | 63 | -------------------------------------------------------------------------------- /tests/18-lkl-host-timer.c: -------------------------------------------------------------------------------- 1 | #define _POSIX_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define NUM_TIMERS 1 9 | #define TEST_DURATION_NS (1000*1000*1000*2UL) 10 | #define TIMER_INTERVAL_NS 1000*1000UL 11 | 12 | // lthread has millisecond accuracy at best 13 | #define SLEEP_DRIFT_ALLOWED_NS (2*1000*1000) 14 | 15 | static unsigned int timer_nums[NUM_TIMERS] = { 0 }; 16 | static unsigned long long timer_fire_count[NUM_TIMERS] = { 0 }; 17 | static void* timers[NUM_TIMERS] = { NULL }; 18 | static unsigned long long timer_next_expected_ns[NUM_TIMERS] = { 0 }; 19 | static int warn = 0; 20 | static int test_complete = 0; 21 | 22 | unsigned long long timestamp_now_ns() { 23 | struct timespec ts; 24 | int res = clock_gettime(CLOCK_REALTIME, &ts); 25 | if (res != 0) { 26 | fprintf(stderr, "clock_gettime() returned %d\n", res); 27 | perror("clock_gettime()"); 28 | return res; 29 | } 30 | return (ts.tv_sec * (1000*1000*1000UL) + ts.tv_nsec); 31 | } 32 | 33 | void timer_fn(void* arg) { 34 | unsigned int num = *((unsigned int*)arg); 35 | unsigned long long now = timestamp_now_ns(); 36 | long long delta_ns = now - timer_next_expected_ns[num]; 37 | timer_fire_count[num]++; 38 | 39 | if (!warn && (delta_ns > SLEEP_DRIFT_ALLOWED_NS || delta_ns < -SLEEP_DRIFT_ALLOWED_NS)) { 40 | fprintf(stderr, "WARN: timer %u fired with delta %lld ns ", 41 | num, delta_ns); 42 | warn = 1; 43 | } 44 | 45 | if (test_complete) 46 | return; 47 | 48 | int res = lkl_host_ops.timer_set_oneshot(timers[num], TIMER_INTERVAL_NS); 49 | if (res != 0) { 50 | fprintf(stderr, "timer_set_oneshot() returned %d after %llu triggers", 51 | res, timer_fire_count[num]); 52 | exit(res); 53 | } 54 | } 55 | 56 | int main() 57 | { 58 | for (unsigned int i = 0; i < NUM_TIMERS; i++) 59 | timer_nums[i] = i; 60 | 61 | // Check timer_alloc() 62 | for (unsigned int i = 0; i < NUM_TIMERS; i++) { 63 | timers[i] = lkl_host_ops.timer_alloc(&timer_fn, &(timer_nums[i])); 64 | if (timers[i] == NULL) { 65 | fprintf(stderr, "%dth timer_alloc() returned NULL\n", i); 66 | return 1; 67 | } 68 | } 69 | 70 | unsigned long long now = timestamp_now_ns(); 71 | for (unsigned int i = 0; i < NUM_TIMERS; i++) { 72 | unsigned long long delta_ns = TIMER_INTERVAL_NS + \ 73 | (i * TIMER_INTERVAL_NS)/NUM_TIMERS; 74 | int res = lkl_host_ops.timer_set_oneshot(timers[i], delta_ns); 75 | timer_next_expected_ns[i] = now + delta_ns; 76 | if (res != 0) { 77 | fprintf(stderr, "timer_set_oneshot() returned %d\n", res); 78 | return 2; 79 | } 80 | } 81 | 82 | sleep((2 * TEST_DURATION_NS) / (1000*1000*1000UL)); 83 | 84 | printf("End of test, stopping timers\n"); 85 | test_complete = 1; 86 | 87 | // Check timer_free() 88 | for (unsigned int i = 0; i < NUM_TIMERS; i++) 89 | lkl_host_ops.timer_free(timers[i]); 90 | 91 | return 0; 92 | } 93 | 94 | -------------------------------------------------------------------------------- /tests/19-lkl-boot.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 42; 3 | } 4 | -------------------------------------------------------------------------------- /tests/20-lkl-disk.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #define _DEFAULT_SOURCE 6 | #define _BSD_SOURCE 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define MAXPATH 100 14 | #define BLOCKSIZE 1024 15 | 16 | char* pretty_print_size(unsigned long bytes) 17 | { 18 | static const char* suffixes[] = { "B", "KiB", "MiB", "GiB" }; 19 | static char buffer[32]; 20 | int unit = 0; 21 | double count = bytes; 22 | while (count > 1024 && unit < 3) { 23 | unit++; 24 | count /= 1024.0; 25 | } 26 | snprintf(buffer, sizeof(buffer), "%.1f%s", count, suffixes[unit]); 27 | return buffer; 28 | } 29 | 30 | char* pretty_print_mode(unsigned int m) 31 | { 32 | static char buffer[32] = {0}; 33 | strncpy(buffer, "---------", sizeof(buffer)); 34 | if (m & S_IRUSR) buffer[0] = 'r'; 35 | if (m & S_IWUSR) buffer[1] = 'w'; 36 | if (m & S_IXUSR) buffer[2] = 'x'; 37 | if (m & S_IRGRP) buffer[3] = 'r'; 38 | if (m & S_IWGRP) buffer[4] = 'w'; 39 | if (m & S_IXGRP) buffer[5] = 'x'; 40 | if (m & S_IROTH) buffer[6] = 'r'; 41 | if (m & S_IWOTH) buffer[7] = 'w'; 42 | if (m & S_IXOTH) buffer[8] = 'x'; 43 | return buffer; 44 | } 45 | 46 | void list_dir(const char* path, int depth) 47 | { 48 | char dirpath[MAXPATH] = {0}; 49 | strncpy(dirpath, path, sizeof(dirpath)); 50 | if (dirpath[strlen(dirpath)-1] != '/') 51 | strncat(dirpath, "/", sizeof(dirpath)); 52 | DIR *d = opendir(dirpath); 53 | if (d == NULL) { 54 | fprintf(stderr, "Error: unable to open dir %s\n", dirpath); 55 | perror("opendir()"); 56 | exit(1); 57 | } 58 | struct dirent *item; 59 | char filepath[MAXPATH] = {0}; 60 | strncpy(filepath, dirpath, sizeof(filepath)); 61 | char *name = filepath + strlen(filepath); 62 | int buflen = sizeof(filepath) - strlen(filepath); 63 | while ((item = readdir(d)) != NULL) { 64 | char *type = "?"; 65 | if (strncmp(item->d_name, "..", 2) == 0 || 66 | strncmp(item->d_name, ".", 1) == 0) 67 | continue; 68 | strncpy(name, item->d_name, buflen); 69 | 70 | if (item->d_type == DT_REG) 71 | type = "-"; 72 | else if (item->d_type == DT_FIFO) 73 | type = "F"; 74 | else if (item->d_type == DT_SOCK) 75 | type = "S"; 76 | else if (item->d_type == DT_CHR) 77 | type = "c"; 78 | else if (item->d_type == DT_BLK) 79 | type = "b"; 80 | else if (item->d_type == DT_DIR) 81 | type = "d"; 82 | else if (item->d_type == DT_LNK) 83 | type = "l"; 84 | 85 | struct stat stat; 86 | int res = lstat(filepath, &stat); 87 | if (res == 0) { 88 | printf("%s%s %ld:%ld %.19s %.19s %.19s %s\t%s\n", 89 | type, pretty_print_mode(stat.st_mode), 90 | (long)stat.st_uid, (long)stat.st_gid, 91 | ctime(&stat.st_atime), ctime(&stat.st_mtime), 92 | ctime(&stat.st_ctime), 93 | pretty_print_size(stat.st_size), filepath); 94 | if (item->d_type == DT_DIR && 95 | strncmp("/sys", filepath, 4) != 0) 96 | list_dir(filepath, depth+1); 97 | } else { 98 | printf("%s????????? ?:? %.19s %.19s %.19s %s\t%s\n", 99 | type, "?", "?", "?", 100 | pretty_print_size(stat.st_size), filepath); 101 | } 102 | } 103 | closedir(d); 104 | } 105 | 106 | int main() { 107 | char buffer[BLOCKSIZE] = {0}; 108 | FILE* f = fopen("/sys/class/block/vda/size", "r"); 109 | if (f == NULL) { 110 | fprintf(stderr, "Error: unable to read disk size\n"); 111 | perror("fopen(/sys/class/block/vda/size)"); 112 | return 1; 113 | } else { 114 | fread(buffer, 1, 512, f); 115 | fclose(f); 116 | unsigned long bytes = strtoul(buffer, NULL, 10); 117 | if (bytes == 0) { 118 | fprintf(stderr, "Error: unable to detect disk size\n"); 119 | return 2; 120 | } 121 | printf(" [*] Detected disk size: %lu bytes\n", bytes); 122 | } 123 | struct statfs fs; 124 | memset(&fs, 0, sizeof(fs)); 125 | int ret = statfs("/", &fs); 126 | if (ret != 0) { 127 | perror("statvfs(/)"); 128 | return ret; 129 | } 130 | printf(" [*] FS type: %08x\n", (int)fs.f_type); 131 | printf(" [*] Free FS blocks: %lld / %lld\n", 132 | (unsigned long long)fs.f_bfree, 133 | (unsigned long long)fs.f_blocks); 134 | printf(" [*] Free space: %lld / %lld bytes\n", 135 | (unsigned long long)(fs.f_bfree*fs.f_bsize), 136 | (unsigned long long)(fs.f_blocks*fs.f_bsize)); 137 | printf(" [*] Enclave file list:\n"); 138 | list_dir("/", 0); 139 | 140 | printf(" [*] Reading test.txt using stdio\n"); 141 | f = fopen("/test.txt", "r"); 142 | if (f == NULL) { 143 | fprintf(stderr, "Error: file /test.txt not found\n"); 144 | perror("fopen()"); 145 | return 2; 146 | } 147 | char *res2 = fgets(buffer, sizeof(buffer), f); 148 | if (res2 == NULL) { 149 | fprintf(stderr, "Error: fgets(/test.txt) returned NULL\n"); 150 | perror("fgets()"); 151 | return 3; 152 | } 153 | if (strcmp("Hello, World!\n", buffer) != 0) 154 | fprintf(stderr, "WARN: read wrong string from /test.txt\n"); 155 | printf(" [*] Read: '%s'\n", buffer); 156 | ret = fclose(f); 157 | if (ret != 0) { 158 | fprintf(stderr, "Error: close(/test.txt) returned %d\n", ret); 159 | perror("fclose()"); 160 | return ret; 161 | } 162 | 163 | for (unsigned int i = 0; i < sizeof(buffer); i++) 164 | buffer[i] = i; 165 | f = fopen("/test_hugefile", "w"); 166 | if (f == NULL) { 167 | perror("fopen(/test_hugefile"); 168 | return 4; 169 | } 170 | unsigned long long total_written = 0; 171 | ssize_t written; 172 | do { 173 | written = fwrite(buffer, 1, sizeof(buffer), f); 174 | total_written += written; 175 | } while (written == sizeof(buffer)); 176 | printf(" [*] Wrote %llu bytes before error\n", total_written); 177 | if (100*total_written < 90*fs.f_blocks*fs.f_bsize) { 178 | fprintf(stderr, "Error: write failed before reaching 90%% of HD\n"); 179 | perror("fwrite()"); 180 | return 5; 181 | } 182 | fclose(f); 183 | unlink("/test_hugefile"); 184 | return 0; 185 | } 186 | -------------------------------------------------------------------------------- /tests/20-lkl-disk.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtth-bfft/muslkl/d6dcfdef0eda1e6ce2bbd02303af6a58e5c5ce44/tests/20-lkl-disk.tar.gz -------------------------------------------------------------------------------- /tests/21-lkl-net.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #define _GNU_SOURCE 10 | #include 11 | 12 | char* ip_to_string(struct sockaddr *addr) 13 | { 14 | static char buf[INET6_ADDRSTRLEN] = {0}; 15 | switch(addr->sa_family) { 16 | case AF_INET: 17 | { struct sockaddr_in *addr_in = (struct sockaddr_in *)addr; 18 | inet_ntop(AF_INET, &(addr_in->sin_addr), buf, sizeof(buf)); 19 | break; } 20 | case AF_INET6: 21 | { struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr; 22 | inet_ntop(AF_INET6, &(addr_in6->sin6_addr), buf, sizeof(buf)); 23 | break; } 24 | default: 25 | snprintf(buf, sizeof(buf), "addr_family=%d", addr->sa_family); 26 | } 27 | return buf; 28 | } 29 | 30 | void print_iff_flags(unsigned int flags) 31 | { 32 | if (flags & IFF_UP) printf(" IFF_UP"); 33 | if (flags & IFF_BROADCAST) printf(" IFF_BROADCAST"); 34 | if (flags & IFF_LOOPBACK) printf(" IFF_LOOPBACK"); 35 | if (flags & IFF_LOWER_UP) printf(" IFF_LOWER_UP"); 36 | } 37 | 38 | void print_iff_list() 39 | { 40 | struct ifaddrs *ifaddrs = NULL; 41 | int res = getifaddrs(&ifaddrs); 42 | if (res != 0) { 43 | fprintf(stderr, "Error: could not get interface list\n"); 44 | perror("getifaddrs()"); 45 | exit(1); 46 | } 47 | 48 | printf(" [*] Interface list:\n"); 49 | for(struct ifaddrs *ifaddr = ifaddrs; ifaddr != NULL; ifaddr = ifaddr->ifa_next) 50 | { 51 | printf(" %s (%s", ifaddr->ifa_name, 52 | (ifaddr->ifa_addr == NULL ? "no addr" : ip_to_string(ifaddr->ifa_addr))); 53 | print_iff_flags(ifaddr->ifa_flags); 54 | printf(")\n"); 55 | } 56 | 57 | int loopback_found = 0; 58 | struct ifaddrs *lo_ipv4 = NULL; 59 | struct ifaddrs *eth0_ipv4 = NULL, *eth0_packet = NULL; 60 | for(struct ifaddrs *ifaddr = ifaddrs; ifaddr != NULL; ifaddr = ifaddr->ifa_next) 61 | { 62 | if ((ifaddr->ifa_flags & IFF_LOOPBACK) != 0) { 63 | loopback_found = 1; 64 | if (ifaddr->ifa_addr->sa_family == AF_INET) 65 | lo_ipv4 = ifaddr; 66 | } 67 | else if ((ifaddr->ifa_flags & IFF_BROADCAST) != 0) { 68 | if (ifaddr->ifa_addr->sa_family == AF_INET) 69 | eth0_ipv4 = ifaddr; 70 | else if (ifaddr->ifa_addr->sa_family == AF_PACKET) 71 | eth0_packet = ifaddr; 72 | } 73 | } 74 | if (!loopback_found) { 75 | fprintf(stderr, "Error: no loopback interface\n"); 76 | exit(2); 77 | } else if (lo_ipv4 == NULL) { 78 | fprintf(stderr, "Error: no address on loopback\n"); 79 | exit(3); 80 | } 81 | if (eth0_packet == NULL) { 82 | fprintf(stderr, "Error: no eth0 interface\n"); 83 | exit(4); 84 | } else if(eth0_ipv4 == NULL) { 85 | fprintf(stderr, "Error: no address on eth0\n"); 86 | exit(5); 87 | } 88 | freeifaddrs(ifaddrs); 89 | } 90 | 91 | int main() { 92 | print_iff_list(); 93 | sleep(2); 94 | return 0; 95 | } 96 | 97 | -------------------------------------------------------------------------------- /tests/60-iozone/Generate_Graphs: -------------------------------------------------------------------------------- 1 | # 2 | # This script will create the Iozone graphs using 3 | # gnuplot. 4 | # 5 | # 6 | # 7 | # ------------------------------------------------ 8 | # YOU MUST PROVIDE A FILE NAME FOR IT TO PROCESS. 9 | # This filename is the name of the file where you 10 | # sent Iozone's output. 11 | # ------------------------------------------------ 12 | 13 | # Generate data base for all of the operation types. 14 | 15 | ./gengnuplot.sh $1 write 16 | ./gengnuplot.sh $1 rewrite 17 | ./gengnuplot.sh $1 read 18 | ./gengnuplot.sh $1 reread 19 | ./gengnuplot.sh $1 randread 20 | ./gengnuplot.sh $1 randwrite 21 | ./gengnuplot.sh $1 bkwdread 22 | ./gengnuplot.sh $1 recrewrite 23 | ./gengnuplot.sh $1 strideread 24 | ./gengnuplot.sh $1 fwrite 25 | ./gengnuplot.sh $1 frewrite 26 | ./gengnuplot.sh $1 fread 27 | ./gengnuplot.sh $1 freread 28 | 29 | # Produce graphs and postscript results. 30 | gnuplot gnu3d.dem 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/60-iozone/Gnuplot.txt: -------------------------------------------------------------------------------- 1 | The script Generate_Graphs will create the 3D surface plots 2 | and display them. It will also produce postscript outputs 3 | for each test and leave them in their respective sub-directory. 4 | 5 | It processes the output from an Iozone run. The output from 6 | Iozone that it is expecting is the text output from 7 | the iozone default behavior. (iozone -a, or iozone -az) 8 | 9 | How to produce graphs: 10 | 11 | Generate_Graphs iozone.out 12 | 13 | The gen_graphs script will: 14 | 1. Create the databases for each type of operation 15 | and then processes them with Gnuplot. 16 | 2. It will display each result on the X11 screen, and 17 | also save a copy in postscript in the test sub-directory. 18 | 19 | 20 | Thanks to Yves Rougy for providing the nifty scripts to help 21 | with the plots. 22 | 23 | 24 | -------------------------------------------------------------------------------- /tests/60-iozone/client_list: -------------------------------------------------------------------------------- 1 | # 2 | # Lines that start with # in column 0 are comments. 3 | # 4 | # There are now two formats supported. 5 | # Format: 3 fields, space delimited. 6 | # Format: 4 fields, space delimited. 7 | # 8 | # Format: 3 fields, space delimited. 9 | # client_name working_dir_on_client path_to_iozone_on_client 10 | # Format: 4 fields, space delimited. 11 | # client_name working_dir_on_client path_to_iozone_on_client path_to_testfile 12 | # 13 | # Example: With two clients (format 3 fields) 14 | # 15 | # client1 /home/user/tmp /home/user/tmp/iozone 16 | # client2 /home/user/tmp /home/user/tmp/iozone 17 | # 18 | # 19 | # Example: With two copies of Iozone on each of the two clients 20 | # (format 3 fields) 21 | # 22 | # client1 /home/user/tmp /home/user/tmp/iozone 23 | # client1 /home/user/tmp /home/user/tmp/iozone 24 | # client2 /home/user/tmp /home/user/tmp/iozone 25 | # client2 /home/user/tmp /home/user/tmp/iozone 26 | # 27 | # Example: With two clients (format 4 fields) 28 | # client1 /home/user/tmp /home/user/tmp/iozone /tmp/foo1 29 | # client2 /home/user/tmp /home/user/tmp/iozone /tmp/foo2 30 | # 31 | # Example: With two copies of Iozone on each of the two clients 32 | # (format 4 fields) 33 | # client1 /home/user/tmp /home/user/tmp/iozone /tmp/foo1 34 | # client1 /home/user/tmp /home/user/tmp/iozone /tmp/foo2 35 | # client2 /home/user/tmp /home/user/tmp/iozone /tmp/foo3 36 | # client2 /home/user/tmp /home/user/tmp/iozone /tmp/foo4 37 | -------------------------------------------------------------------------------- /tests/60-iozone/gengnuplot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2001 Yves Rougy Yves@Rougy.net 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | 20 | 21 | cp $1 iozone_gen_out 22 | file_name=iozone_gen_out 23 | #set -x 24 | 25 | write_gnuplot_file() { 26 | echo \#test : $query 27 | case $query in 28 | (write) awk '$1 ~ /^[0-9]+/ { print $1 " " $2 " " $3 }' < $file_name ;; 29 | (rewrite) awk '$1 ~ /^[0-9]+/ { print $1 " " $2 " " $4 }' < $file_name ;; 30 | (read) awk '$1 ~ /^[0-9]+/ { print $1 " " $2 " " $5 }' < $file_name ;; 31 | (reread) awk '$1 ~ /^[0-9]+/ { print $1 " " $2 " " $6 }' < $file_name ;; 32 | (randread) awk '$1 ~ /^[0-9]+/ { print $1 " " $2 " " $7 }' < $file_name ;; 33 | (randwrite) awk '$1 ~ /^[0-9]+/ { print $1 " " $2 " " $8 }' < $file_name ;; 34 | (bkwdread) awk '$1 ~ /^[0-9]+/ { print $1 " " $2 " " $9 }' < $file_name ;; 35 | (recrewrite) awk '$1 ~ /^[0-9]+/ { print $1 " " $2 " " $10 }' < $file_name ;; 36 | (strideread) awk '$1 ~ /^[0-9]+/ { print $1 " " $2 " " $11 }' < $file_name ;; 37 | (fwrite) awk '$1 ~ /^[0-9]+/ { print $1 " " $2 " " $12 }' < $file_name ;; 38 | (frewrite) awk '$1 ~ /^[0-9]+/ { print $1 " " $2 " " $13 }' < $file_name ;; 39 | (fread) awk '$1 ~ /^[0-9]+/ { print $1 " " $2 " " $14 }' < $file_name ;; 40 | (freread) awk '$1 ~ /^[0-9]+/ { print $1 " " $2 " " $15 }' < $file_name ;; 41 | (*) echo "Usage : gengnuplot.sh " >> /dev/stderr ; 42 | echo "filename is the output of iozone -a" >> /dev/stderr ; 43 | echo "test is one of write rewrite read reread randread randwrite bkwdread recrewrite strideread fwrite frewrite fread freread" >> /dev/stderr ;; 44 | esac } 45 | 46 | #filename=$1 47 | filename=iozone_gen_out 48 | query=$2 49 | if (! [ -e $query ] ) ; then mkdir $query; fi 50 | if ( [ $# -eq 2 ] ) ; 51 | then 52 | write_gnuplot_file > $query/`basename $file_name.gnuplot` 53 | else 54 | echo "Usage : gengnuplot.sh " 2>&1 55 | echo "filename is the output of iozone -a" 2>&1 56 | echo "test is one of write rewrite read reread randread randwrite bkwdread recrewrite strideread fwrite frewrite fread freread" 2>&1 57 | fi 58 | -------------------------------------------------------------------------------- /tests/60-iozone/gnu3d.dem: -------------------------------------------------------------------------------- 1 | # 2 | # $Id: 3D plot of performance 3 | # 4 | # Processes files that were created by Generate_Graphs 5 | # and displays the results. Also, saves a postscript copy. 6 | # 7 | # Don Capps 8 | 9 | dirs = "write rewrite read reread randread randwrite bkwdread recrewrite strideread fwrite frewrite fread freread" 10 | titles = "Write ReWrite Read Reread Random_read Random_write Read_Backwards Record_rewrite Stride_read Fwrite Frewrite Fread Freread" 11 | 12 | file(n) = sprintf("%s/iozone_gen_out.gnuplot", word(dirs,n)) 13 | outfile(n) = sprintf("%s/%s.ps", word(dirs,n), word(dirs,n)) 14 | title(n) = word(titles,n) 15 | 16 | set title "Iozone performance" 17 | set grid lt 2 lw 1 18 | set surface 19 | set parametric 20 | set xtics 21 | set ytics 22 | set logscale x 2 23 | set logscale y 2 24 | set xlabel "File size in 2^n KBytes" 25 | set ylabel "Record size in 2^n Kbytes" 26 | set zlabel "Kbytes/sec" 27 | set style data lines 28 | set dgrid3d 80,80,3 29 | 30 | i = 1 31 | set terminal x11 32 | set output 33 | splot file(i) title title(i) 34 | pause -1 "Hit return to continue" 35 | set terminal postscript color 36 | set output outfile(i) 37 | replot 38 | 39 | i = 2 40 | set terminal x11 41 | set output 42 | replot 43 | pause -1 "Hit return to continue" 44 | set terminal postscript color 45 | set output outfile(i) 46 | replot 47 | 48 | i = 3 49 | set terminal x11 50 | set output 51 | replot 52 | pause -1 "Hit return to continue" 53 | set terminal postscript color 54 | set output outfile(i) 55 | replot 56 | 57 | i = 4 58 | set terminal x11 59 | set output 60 | replot 61 | pause -1 "Hit return to continue" 62 | set terminal postscript color 63 | set output outfile(i) 64 | replot 65 | 66 | i = 5 67 | set terminal x11 68 | set output 69 | replot 70 | pause -1 "Hit return to continue" 71 | set terminal postscript color 72 | set output outfile(i) 73 | replot 74 | 75 | i = 6 76 | set terminal x11 77 | set output 78 | replot 79 | pause -1 "Hit return to continue" 80 | set terminal postscript color 81 | set output outfile(i) 82 | replot 83 | 84 | i = 7 85 | set terminal x11 86 | set output 87 | replot 88 | pause -1 "Hit return to continue" 89 | set terminal postscript color 90 | set output outfile(i) 91 | replot 92 | 93 | i = 8 94 | set terminal x11 95 | set output 96 | replot 97 | pause -1 "Hit return to continue" 98 | set terminal postscript color 99 | set output outfile(i) 100 | replot 101 | 102 | i = 9 103 | set terminal x11 104 | set output 105 | replot 106 | pause -1 "Hit return to continue" 107 | set terminal postscript color 108 | set output outfile(i) 109 | replot 110 | 111 | i = 10 112 | set terminal x11 113 | set output 114 | replot 115 | pause -1 "Hit return to continue" 116 | set terminal postscript color 117 | set output outfile(i) 118 | replot 119 | 120 | i = 11 121 | set terminal x11 122 | set output 123 | replot 124 | pause -1 "Hit return to continue" 125 | set terminal postscript color 126 | set output outfile(i) 127 | replot 128 | 129 | i = 12 130 | set terminal x11 131 | set output 132 | replot 133 | pause -1 "Hit return to continue" 134 | set terminal postscript color 135 | set output outfile(i) 136 | replot 137 | 138 | i = 13 139 | set terminal x11 140 | set output 141 | replot 142 | pause -1 "Hit return to continue" 143 | set terminal postscript color 144 | set output outfile(i) 145 | replot 146 | 147 | -------------------------------------------------------------------------------- /tests/60-iozone/gnuplot.dem: -------------------------------------------------------------------------------- 1 | # 2 | # $Id: Plot of latency versus offset in a file 3 | # 4 | # Requires data file "wol.dat" from this directory, 5 | # so change current working directory to this directory before running. 6 | # 7 | 8 | set title "File system write latency " 9 | set autoscale x 10 | set xtics 11 | set xlabel "Offset in file (KB)" 12 | set ylabel "Latency in Microseconds" 13 | plot 'wol.dat' using 1:2 title "Latency Plot" with lines 14 | pause -1 "Hit return to continue" 15 | 16 | # 17 | # $Id: Plot of latency versus offset in a file 18 | # 19 | # Requires data file "rwol.dat" from this directory, 20 | # so change current working directory to this directory before running. 21 | # 22 | 23 | set title "File system re-write latency " 24 | set autoscale x 25 | set xtics 26 | set xlabel "Offset in file (KB)" 27 | set ylabel "Latency in Microseconds" 28 | plot 'rwol.dat' using 1:2 title "Latency Plot" with lines 29 | pause -1 "Hit return to continue" 30 | 31 | # 32 | # $Id: Plot of latency versus offset in a file 33 | # 34 | # Requires data file "rol.dat" from this directory, 35 | # so change current working directory to this directory before running. 36 | # 37 | 38 | set title "File system read latency " 39 | set autoscale x 40 | set xtics 41 | set xlabel "Offset in file (KB)" 42 | set ylabel "Latency in Microseconds" 43 | plot 'rol.dat' using 1:2 title "Latency Plot" with lines 44 | pause -1 "Hit return to continue" 45 | 46 | # 47 | # $Id: Plot of latency versus offset in a file 48 | # 49 | # Requires data file "rrol.dat" from this directory, 50 | # so change current working directory to this directory before running. 51 | # 52 | 53 | set title "File system re-read latency " 54 | set autoscale x 55 | set xtics 56 | set xlabel "Offset in file (KB)" 57 | set ylabel "Latency in Microseconds" 58 | plot 'rrol.dat' using 1:2 title "Latency Plot" with lines 59 | pause -1 "Hit return to continue" 60 | 61 | -------------------------------------------------------------------------------- /tests/60-iozone/gnuplotps.dem: -------------------------------------------------------------------------------- 1 | # 2 | # $Id: Plot of latency versus offset in a file 3 | # 4 | # Requires data file "wol.dat" from this directory, 5 | # so change current working directory to this directory before running. 6 | # 7 | 8 | set title "File system write latency " 9 | set terminal postscript 10 | set output "gnu_wol.ps" 11 | set autoscale x 12 | set xtics 13 | set xlabel "Offset in file (KB)" 14 | set ylabel "Latency in Microseconds" 15 | plot 'wol.dat' using 1:2 title "Latency Plot" with lines 16 | # 17 | # $Id: Plot of latency versus offset in a file 18 | # 19 | # Requires data file "rwol.dat" from this directory, 20 | # so change current working directory to this directory before running. 21 | # 22 | 23 | set title "File system re-write latency " 24 | set terminal postscript 25 | set output "gnu_rwol.ps" 26 | set autoscale x 27 | set xtics 28 | set xlabel "Offset in file (KB)" 29 | set ylabel "Latency in Microseconds" 30 | plot 'rwol.dat' using 1:2 title "Latency Plot" with lines 31 | 32 | # 33 | # $Id: Plot of latency versus offset in a file 34 | # 35 | # Requires data file "rol.dat" from this directory, 36 | # so change current working directory to this directory before running. 37 | # 38 | 39 | set title "File system read latency " 40 | set autoscale x 41 | set xtics 42 | set xlabel "Offset in file (KB)" 43 | set ylabel "Latency in Microseconds" 44 | set terminal postscript 45 | set output "gnu_rol.ps" 46 | plot 'rol.dat' using 1:2 title "Latency Plot" with lines 47 | 48 | # 49 | # $Id: Plot of latency versus offset in a file 50 | # 51 | # Requires data file "rrol.dat" from this directory, 52 | # so change current working directory to this directory before running. 53 | # 54 | 55 | set title "File system re-read latency " 56 | set terminal postscript 57 | set output "gnu_rrol.ps" 58 | set autoscale x 59 | set xtics 60 | set xlabel "Offset in file (KB)" 61 | set ylabel "Latency in Microseconds" 62 | plot 'rrol.dat' using 1:2 title "Latency Plot" with lines 63 | 64 | -------------------------------------------------------------------------------- /tests/60-iozone/iozone_visualizer.pl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtth-bfft/muslkl/d6dcfdef0eda1e6ce2bbd02303af6a58e5c5ce44/tests/60-iozone/iozone_visualizer.pl -------------------------------------------------------------------------------- /tests/60-iozone/libasync.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Library for Posix async read operations with hints. 3 | * Author: Don Capps 4 | * Company: Iozone 5 | * Date: 4/24/1998 6 | * 7 | * Two models are supported. First model is a replacement for read() where the async 8 | * operations are performed and the requested data is bcopy()-ed back into the users 9 | * buffer. The second model is a new version of read() where the caller does not 10 | * supply the address of the buffer but instead is returned an address to the 11 | * location of the data. The second model eliminates a bcopy from the path. 12 | * 13 | * To use model #1: 14 | * 1. Call async_init(&pointer_on_stack,fd,direct_flag); 15 | * The fd is the file descriptor for the async operations. 16 | * The direct_flag sets VX_DIRECT 17 | * 18 | * 2. Call async_read(gc, fd, ubuffer, offset, size, stride, max, depth) 19 | * Where: 20 | * gc ............ is the pointer on the stack 21 | * fd ............ is the file descriptor 22 | * ubuffer ....... is the address of the user buffer. 23 | * offset ........ is the offset in the file to begin reading 24 | * size .......... is the size of the transfer. 25 | * stride ........ is the distance, in size units, to space the async reads. 26 | * max ........... is the max size of the file to be read. 27 | * depth ......... is the number of async operations to perform. 28 | * 29 | * 3. Call end_async(gc) when finished. 30 | * Where: 31 | * gc ............ is the pointer on the stack. 32 | * 33 | * To use model #2: 34 | * 1. Call async_init(&pointer_on_stack,fd,direct_flag); 35 | * The fd is the file descriptor for the async operations. 36 | * The direct_flag sets VX_DIRECT 37 | * 2. Call async_read(gc, fd, &ubuffer, offset, size, stride, max, depth) 38 | * Where: 39 | * gc ............ is the pointer on the stack 40 | * fd ............ is the file descriptor 41 | * ubuffer ....... is the address of a pointer that will be filled in 42 | * by the async library. 43 | * offset ........ is the offset in the file to begin reading 44 | * size .......... is the size of the transfer. 45 | * stride ........ is the distance, in size units, to space the async reads. 46 | * max ........... is the max size of the file to be read. 47 | * depth ......... is the number of async operations to perform. 48 | * 49 | * 3. Call async_release(gc) when finished with the data that was returned. 50 | * This allows the async library to reuse the memory that was filled in 51 | * and returned to the user. 52 | * 53 | * 4. Call end_async(gc) when finished. 54 | * Where: 55 | * gc ............ is the pointer on the stack. 56 | * 57 | * To use model #1: (WRITES) 58 | * 1. Call async_init(&pointer_on_stack,fd,direct_flag); 59 | * The fd is the file descriptor for the async operations. 60 | * 61 | * 2. Call async_write(gc, fd, ubuffer, size, offset, depth) 62 | * Where: 63 | * gc ............ is the pointer on the stack 64 | * fd ............ is the file descriptor 65 | * ubuffer ....... is the address of the user buffer. 66 | * size .......... is the size of the transfer. 67 | * offset ........ is the offset in the file to begin reading 68 | * depth ......... is the number of async operations to perform. 69 | * 70 | * 4. Call end_async(gc) when finished. 71 | * Where: 72 | * gc ............ is the pointer on the stack. 73 | * 74 | * Notes: 75 | * The intended use is to replace calls to read() with calls to 76 | * async_read() and allow the user to make suggestions on 77 | * what kind of async read-ahead would be nice to have. 78 | * The first transfer requested is guarenteed to be complete 79 | * before returning to the caller. The async operations will 80 | * be started and will also be guarenteed to have completed 81 | * if the next call specifies its first request to be one 82 | * that was previously performed with an async operation. 83 | * 84 | * The async_read_no_copy() function allows the async operations 85 | * to return the data to the user and not have to perform 86 | * a bcopy of the data back into the user specified buffer 87 | * location. This model is faster but assumes that the user 88 | * application has been modified to work with this model. 89 | * 90 | * The async_write() is intended to enhance the performance of 91 | * initial writes to a file. This is the slowest case in the write 92 | * path as it must perform meta-data allocations and wait. 93 | */ 94 | 95 | #include 96 | #include 97 | 98 | #if defined(_LARGEFILE64_SOURCE) && !defined(__LP64__) 99 | # define aio_error aio_error64 100 | # define aio_return aio_return64 101 | # define aio_read aio_read64 102 | # define aio_cancel aio_cancel64 103 | # define aio_write aio_write64 104 | #endif 105 | 106 | #if defined(solaris) || defined(linux) || defined(SCO_Unixware_gcc) || defined(__NetBSD__) 107 | #else 108 | #include 109 | #endif 110 | #include 111 | #include 112 | #ifndef bsd4_4 113 | #include 114 | #endif 115 | #ifdef VXFS 116 | #include 117 | #endif 118 | 119 | #if defined(OSFV5) || defined(linux) 120 | #include 121 | #endif 122 | 123 | #if defined(linux) 124 | #include 125 | #include 126 | #include 127 | #endif 128 | 129 | #if (defined(solaris) && defined(__LP64__)) || defined(__s390x__) || defined(__FreeBSD__) || defined(__NetBSD__) 130 | /* If we are building for 64-bit Solaris, all functions that return pointers 131 | * must be declared before they are used; otherwise the compiler will assume 132 | * that they return ints and the top 32 bits of the pointer will be lost, 133 | * causing segmentation faults. The following includes take care of this. 134 | * It should be safe to add these for all other OSs too, but we're only 135 | * doing it for Solaris now in case another OS turns out to be a special case. 136 | */ 137 | #include 138 | #include 139 | #include /* For the BSD string functions */ 140 | #endif 141 | 142 | static void mbcopy(const char *source, char *dest, size_t len); 143 | 144 | 145 | #if !defined(solaris) && !defined(off64_t) && !defined(_OFF64_T) && !defined(__off64_t_defined) && !defined(SCO_Unixware_gcc) 146 | # if defined(bsd4_4) 147 | typedef off_t off64_t; 148 | # else 149 | typedef long long off64_t; 150 | # endif 151 | #endif 152 | #if defined(OSFV5) 153 | #include 154 | #endif 155 | 156 | 157 | extern long long page_size; 158 | extern int one; 159 | /* 160 | * Internal cache entrys. Each entry on the global 161 | * cache, pointed to by async_init(gc) will be of 162 | * this structure type. 163 | */ 164 | static const char version[] = "Libasync Version $Revision: 3.32 $"; 165 | struct cache_ent { 166 | #if defined(_LARGEFILE64_SOURCE) && defined(__CrayX1__) 167 | aiocb64_t myaiocb; /* For use in large file mode */ 168 | #elif defined(_LARGEFILE64_SOURCE) && !defined(__LP64__) 169 | struct aiocb64 myaiocb; /* For use in large file mode */ 170 | #else 171 | struct aiocb myaiocb; 172 | #endif 173 | long long fd; /* File descriptor */ 174 | long long size; /* Size of the transfer */ 175 | struct cache_ent *forward; /* link to next element on cache list */ 176 | struct cache_ent *back; /* link to previous element on the cache list */ 177 | long long direct; /* flag to indicate if the buffer should be */ 178 | /* de-allocated by library */ 179 | char *real_address; /* Real address to free */ 180 | 181 | volatile void *oldbuf; /* Used for firewall to prevent in flight */ 182 | /* accidents */ 183 | int oldfd; /* Used for firewall to prevent in flight */ 184 | /* accidents */ 185 | size_t oldsize; /* Used for firewall to prevent in flight */ 186 | /* accidents */ 187 | }; 188 | 189 | /* 190 | * Head of the cache list 191 | */ 192 | struct cache { 193 | struct cache_ent *head; /* Head of cache list */ 194 | struct cache_ent *tail; /* tail of cache list */ 195 | struct cache_ent *inuse_head; /* head of in-use list */ 196 | long long count; /* How many elements on the cache list */ 197 | struct cache_ent *w_head; /* Head of cache list */ 198 | struct cache_ent *w_tail; /* tail of cache list */ 199 | long long w_count; /* How many elements on the write list */ 200 | }; 201 | 202 | long long max_depth; 203 | extern int errno; 204 | static struct cache_ent *alloc_cache(); 205 | static struct cache_ent *incache(); 206 | 207 | #ifdef HAVE_ANSIC_C 208 | void async_init(struct cache **,int, int); 209 | int async_suspend(struct cache_ent *); 210 | void end_async(struct cache *); 211 | void takeoff_cache(struct cache *, struct cache_ent *); 212 | void del_cache(struct cache *); 213 | void putoninuse(struct cache *,struct cache_ent *); 214 | void takeoffinuse(struct cache *); 215 | struct cache_ent * allocate_write_buffer( struct cache *, long long , long long ,long long, off64_t, long long, long long, char *, char *); 216 | void async_put_on_write_queue(struct cache *, struct cache_ent *); 217 | void async_write_finish(struct cache *); 218 | void async_wait_for_write(struct cache *); 219 | int async_read(struct cache *, long long , char *, off64_t, long long, long long, off64_t, long long); 220 | struct cache_ent * alloc_cache(struct cache *gc,long long fd,off64_t offset,long long size,long long op); 221 | struct cache_ent * incache(struct cache *, long long, off64_t, long long); 222 | int async_read_no_copy(struct cache *, long long, char **, off64_t, long long, long long, off64_t, long long); 223 | void async_release(struct cache *gc); 224 | size_t async_write(struct cache *,long long, char *, long long, off64_t, long long); 225 | size_t async_write_no_copy(struct cache *gc,long long fd,char *buffer,long long size,off64_t offset,long long depth,char *free_addr); 226 | #else 227 | void async_init(); 228 | void end_async(); 229 | int async_suspend(); 230 | int async_read(); 231 | void async_release(); 232 | struct cache_ent *allocate_write_buffer(); 233 | size_t async_write(); 234 | void async_wait_for_write(); 235 | void async_put_on_write_queue(); 236 | void async_write_finish(); 237 | struct cache_ent * alloc_cache(); 238 | #endif 239 | 240 | /* On Solaris _LP64 will be defined by if we're compiling 241 | * as a 64-bit binary. Make sure that __LP64__ gets defined in this case, 242 | * too -- it should be defined on the compiler command line, but let's 243 | * not rely on this. 244 | */ 245 | #if defined(_LP64) 246 | #if !defined(__LP64__) 247 | #define __LP64__ 248 | #endif 249 | #endif 250 | 251 | 252 | /***********************************************/ 253 | /* Initialization routine to setup the library */ 254 | /***********************************************/ 255 | #ifdef HAVE_ANSIC_C 256 | void async_init(struct cache **gc,int fd,int flag) 257 | #else 258 | void 259 | async_init(gc,fd,flag) 260 | struct cache **gc; 261 | int fd; 262 | int flag; 263 | #endif 264 | { 265 | #ifdef VXFS 266 | if(flag) 267 | ioctl(fd,VX_SETCACHE,VX_DIRECT); 268 | #endif 269 | if(*gc) 270 | { 271 | printf("Warning calling async_init two times ?\n"); 272 | return; 273 | } 274 | *gc=(struct cache *)malloc((size_t)sizeof(struct cache)); 275 | if(*gc == 0) 276 | { 277 | printf("Malloc failed\n"); 278 | exit(174); 279 | } 280 | bzero(*gc,sizeof(struct cache)); 281 | #if defined(__AIX__) || defined(SCO_Unixware_gcc) 282 | max_depth=500; 283 | #else 284 | max_depth=sysconf(_SC_AIO_MAX); 285 | #endif 286 | } 287 | 288 | /***********************************************/ 289 | /* Tear down routine to shutdown the library */ 290 | /***********************************************/ 291 | #ifdef HAVE_ANSIC_C 292 | void end_async(struct cache *gc) 293 | #else 294 | void 295 | end_async(gc) 296 | struct cache *gc; 297 | #endif 298 | { 299 | del_cache(gc); 300 | async_write_finish(gc); 301 | free((void *)gc); 302 | } 303 | 304 | /***********************************************/ 305 | /* Wait for a request to finish */ 306 | /***********************************************/ 307 | #ifdef HAVE_ANSIC_C 308 | int 309 | async_suspend(struct cache_ent *ce) 310 | #else 311 | int 312 | async_suspend(ce) 313 | struct cache_ent *ce; 314 | #endif 315 | { 316 | #ifdef _LARGEFILE64_SOURCE 317 | #ifdef __LP64__ 318 | const struct aiocb * const cblist[1] = {&ce->myaiocb}; 319 | #else 320 | const struct aiocb64 * const cblist[1] = {&ce->myaiocb}; 321 | #endif 322 | #else 323 | const struct aiocb * const cblist[1] = {&ce->myaiocb}; 324 | #endif 325 | 326 | #ifdef _LARGEFILE64_SOURCE 327 | #ifdef __LP64__ 328 | return aio_suspend(cblist, 1, NULL); 329 | #else 330 | return aio_suspend64(cblist, 1, NULL); 331 | #endif 332 | #else 333 | return aio_suspend(cblist, 1, NULL); 334 | #endif 335 | } 336 | 337 | /************************************************************************* 338 | * This routine is a generic async reader assist funtion. It takes 339 | * the same calling parameters as read() but also extends the 340 | * interface to include: 341 | * stride ..... For the async reads, what is the distance, in size units, 342 | * to space the reads. Note: Stride of 0 indicates that 343 | * you do not want any read-ahead. 344 | * max ..... What is the maximum file offset for this operation. 345 | * depth ..... How much read-ahead do you want. 346 | * 347 | * The calls to this will guarentee to complete the read() operation 348 | * before returning to the caller. The completion may occur in two 349 | * ways. First the operation may be completed by calling aio_read() 350 | * and then waiting for it to complete. Second the operation may be 351 | * completed by copying the data from a cache of previously completed 352 | * async operations. 353 | * In the event the read to be satisfied is not in the cache then a 354 | * series of async operations will be scheduled and then the first 355 | * async read will be completed. In the event that the read() can be 356 | * satisfied from the cache then the data is copied back to the 357 | * user buffer and a series of async reads will be initiated. If a 358 | * read is issued and the cache contains data and the read can not 359 | * be satisfied from the cache, then the cache is discarded, and 360 | * a new cache is constructed. 361 | * Note: All operations are aio_read(). The series will be issued 362 | * as asyncs in the order requested. After all are in flight 363 | * then the code will wait for the manditory first read. 364 | *************************************************************************/ 365 | 366 | #ifdef HAVE_ANSIC_C 367 | int async_read(struct cache *gc, long long fd, char *ubuffer, off64_t offset, 368 | long long size, long long stride, off64_t max, long long depth) 369 | #else 370 | int 371 | async_read(gc, fd, ubuffer, offset, size, stride, max, depth) 372 | struct cache *gc; 373 | long long fd; 374 | char *ubuffer; 375 | off64_t offset; 376 | long long size; 377 | long long stride; 378 | off64_t max; 379 | long long depth; 380 | #endif 381 | { 382 | off64_t a_offset,r_offset; 383 | long long a_size; 384 | struct cache_ent *ce,*first_ce=0; 385 | long long i; 386 | ssize_t retval=0; 387 | ssize_t ret; 388 | long long start = 0; 389 | long long del_read=0; 390 | 391 | a_offset=offset; 392 | a_size = size; 393 | /* 394 | * Check to see if it can be completed from the cache 395 | */ 396 | if((ce=(struct cache_ent *)incache(gc,fd,offset,size))) 397 | { 398 | while((ret=aio_error(&ce->myaiocb))== EINPROGRESS) 399 | { 400 | async_suspend(ce); 401 | } 402 | if(ret) 403 | { 404 | printf("aio_error 1: ret %zd %d\n",ret,errno); 405 | } 406 | retval=aio_return(&ce->myaiocb); 407 | if(retval > 0) 408 | { 409 | mbcopy((char *)ce->myaiocb.aio_buf,(char *)ubuffer,(size_t)retval); 410 | } 411 | if(retval < ce->myaiocb.aio_nbytes) 412 | { 413 | printf("aio_return error1: ret %zd %d\n",retval,errno); 414 | printf("aio_return error1: fd %d offset %lld buffer %p size %zd Opcode %d\n", 415 | ce->myaiocb.aio_fildes, 416 | (long long)ce->myaiocb.aio_offset, 417 | ce->myaiocb.aio_buf, 418 | ce->myaiocb.aio_nbytes, 419 | ce->myaiocb.aio_lio_opcode 420 | ); 421 | } 422 | ce->direct=0; 423 | takeoff_cache(gc,ce); 424 | }else 425 | { 426 | /* 427 | * Clear the cache and issue the first request async() 428 | */ 429 | del_cache(gc); 430 | del_read++; 431 | first_ce=alloc_cache(gc,fd,offset,size,(long long)LIO_READ); 432 | again: 433 | ret=aio_read(&first_ce->myaiocb); 434 | if(ret!=0) 435 | { 436 | if(errno==EAGAIN) 437 | goto again; 438 | else 439 | printf("error returned from aio_read(). Ret %zd errno %d\n",ret,errno); 440 | } 441 | } 442 | if(stride==0) /* User does not want read-ahead */ 443 | goto out; 444 | if(a_offset<0) /* Before beginning of file */ 445 | goto out; 446 | if(a_offset+size>max) /* After end of file */ 447 | goto out; 448 | if(depth >=(max_depth-1)) 449 | depth=max_depth-1; 450 | if(depth==0) 451 | goto out; 452 | if(gc->count > 1) 453 | start=depth-1; 454 | for(i=start;i max) 460 | continue; 461 | if((ce=incache(gc,fd,r_offset,a_size))) 462 | continue; 463 | ce=alloc_cache(gc,fd,r_offset,a_size,(long long)LIO_READ); 464 | ret=aio_read(&ce->myaiocb); 465 | if(ret!=0) 466 | { 467 | takeoff_cache(gc,ce); 468 | break; 469 | } 470 | } 471 | out: 472 | if(del_read) /* Wait for the first read to complete */ 473 | { 474 | while((ret=aio_error(&first_ce->myaiocb))== EINPROGRESS) 475 | { 476 | async_suspend(first_ce); 477 | } 478 | if(ret) 479 | printf("aio_error 2: ret %zd %d\n",ret,errno); 480 | retval=aio_return(&first_ce->myaiocb); 481 | if(retval < first_ce->myaiocb.aio_nbytes) 482 | { 483 | printf("aio_return error2: ret %zd %d\n",retval,errno); 484 | printf("aio_return error2: fd %d offset %lld buffer %p size %zd Opcode %d\n", 485 | first_ce->myaiocb.aio_fildes, 486 | (long long)first_ce->myaiocb.aio_offset, 487 | first_ce->myaiocb.aio_buf, 488 | first_ce->myaiocb.aio_nbytes, 489 | first_ce->myaiocb.aio_lio_opcode 490 | ); 491 | } 492 | if(retval > 0) 493 | { 494 | mbcopy((char *)first_ce->myaiocb.aio_buf,(char *)ubuffer,(size_t)retval); 495 | } 496 | first_ce->direct=0; 497 | takeoff_cache(gc,first_ce); 498 | } 499 | return((int)retval); 500 | } 501 | 502 | /************************************************************************ 503 | * This routine allocates a cache_entry. It contains the 504 | * aiocb block as well as linkage for use in the cache mechanism. 505 | * The space allocated here will be released after the cache entry 506 | * has been consumed. The routine takeoff_cache() will be called 507 | * after the data has been copied to user buffer or when the 508 | * cache is purged. The routine takeoff_cache() will also release 509 | * all memory associated with this cache entry. 510 | ************************************************************************/ 511 | 512 | #ifdef HAVE_ANSIC_C 513 | struct cache_ent * alloc_cache(struct cache *gc,long long fd,off64_t offset,long long size,long long op) 514 | #else 515 | struct cache_ent * 516 | alloc_cache(gc,fd,offset,size,op) 517 | struct cache *gc; 518 | long long fd,size,op; 519 | off64_t offset; 520 | #endif 521 | { 522 | struct cache_ent *ce; 523 | intptr_t temp; 524 | ce=(struct cache_ent *)malloc((size_t)sizeof(struct cache_ent)); 525 | if(ce == (struct cache_ent *)0) 526 | { 527 | printf("Malloc failed\n"); 528 | exit(175); 529 | } 530 | bzero(ce,sizeof(struct cache_ent)); 531 | ce->myaiocb.aio_fildes=(int)fd; 532 | ce->myaiocb.aio_offset=(off64_t)offset; 533 | ce->real_address = malloc((size_t)(size+page_size)); 534 | temp = (intptr_t)ce->real_address; 535 | temp = (temp+page_size) & ~(page_size-1); 536 | ce->myaiocb.aio_buf=(volatile void *)temp; 537 | if(ce->myaiocb.aio_buf == NULL) 538 | { 539 | printf("Malloc failed\n"); 540 | exit(176); 541 | } 542 | /*bzero(ce->myaiocb.aio_buf,(size_t)size);*/ 543 | ce->myaiocb.aio_reqprio=0; 544 | ce->myaiocb.aio_nbytes=(size_t)size; 545 | ce->myaiocb.aio_sigevent.sigev_notify=SIGEV_NONE; 546 | ce->myaiocb.aio_lio_opcode=(int)op; 547 | ce->fd=(int)fd; 548 | ce->forward=0; 549 | ce->back=gc->tail; 550 | if(gc->tail) 551 | gc->tail->forward = ce; 552 | gc->tail= ce; 553 | if(!gc->head) 554 | gc->head=ce; 555 | gc->count++; 556 | return(ce); 557 | } 558 | 559 | /************************************************************************ 560 | * This routine checks to see if the requested data is in the 561 | * cache. 562 | *************************************************************************/ 563 | #ifdef HAVE_ANSIC_C 564 | struct cache_ent * 565 | incache(struct cache *gc, long long fd, off64_t offset, long long size) 566 | #else 567 | struct cache_ent * 568 | incache(gc,fd,offset,size) 569 | struct cache *gc; 570 | long long fd,size; 571 | off64_t offset; 572 | #endif 573 | { 574 | struct cache_ent *move; 575 | if(gc->head==0) 576 | { 577 | return(0); 578 | } 579 | move=gc->head; 580 | while(move) 581 | { 582 | if((move->fd == fd) && (move->myaiocb.aio_offset==(off64_t)offset) && 583 | ((size_t)size==move->myaiocb.aio_nbytes)) 584 | { 585 | return(move); 586 | } 587 | move=move->forward; 588 | } 589 | return(0); 590 | } 591 | 592 | /************************************************************************ 593 | * This routine removes a specific cache entry from the cache, and 594 | * releases all memory associated witht the cache entry (if not direct). 595 | *************************************************************************/ 596 | 597 | void 598 | takeoff_cache(struct cache *gc, struct cache_ent *ce) 599 | { 600 | struct cache_ent *move; 601 | long long found; 602 | move=gc->head; 603 | if(move==ce) /* Head of list */ 604 | { 605 | 606 | gc->head=ce->forward; 607 | if(gc->head) 608 | gc->head->back=0; 609 | else 610 | gc->tail = 0; 611 | if(!ce->direct) 612 | { 613 | free((void *)(ce->real_address)); 614 | free((void *)ce); 615 | } 616 | gc->count--; 617 | return; 618 | } 619 | found=0; 620 | while(move) 621 | { 622 | if(move==ce) 623 | { 624 | if(move->forward) 625 | { 626 | move->forward->back=move->back; 627 | } 628 | if(move->back) 629 | { 630 | move->back->forward=move->forward; 631 | } 632 | found=1; 633 | break; 634 | } 635 | else 636 | { 637 | move=move->forward; 638 | } 639 | } 640 | if(gc->head == ce) 641 | gc->tail = ce; 642 | if(!found) 643 | printf("Internal Error in takeoff cache\n"); 644 | move=gc->head; 645 | if(!ce->direct) 646 | { 647 | free((void *)(ce->real_address)); 648 | free((void *)ce); 649 | } 650 | gc->count--; 651 | } 652 | 653 | /************************************************************************ 654 | * This routine is used to purge the entire cache. This is called when 655 | * the cache contains data but the incomming read was not able to 656 | * be satisfied from the cache. This indicates that the previous 657 | * async read-ahead was not correct and a new pattern is emerging. 658 | ************************************************************************/ 659 | #ifdef HAVE_ANSIC_C 660 | void 661 | del_cache(struct cache *gc) 662 | #else 663 | void 664 | del_cache(gc) 665 | struct cache *gc; 666 | #endif 667 | { 668 | struct cache_ent *ce; 669 | ssize_t ret; 670 | ce=gc->head; 671 | while(1) 672 | { 673 | ce=gc->head; 674 | if(ce==0) 675 | return; 676 | while((ret = aio_cancel(0,&ce->myaiocb))==AIO_NOTCANCELED) 677 | ; 678 | 679 | ret = aio_return(&ce->myaiocb); 680 | ce->direct=0; 681 | takeoff_cache(gc,ce); /* remove from cache */ 682 | } 683 | } 684 | 685 | /************************************************************************ 686 | * Like its sister async_read() this function performs async I/O for 687 | * all buffers but it differs in that it expects the caller to 688 | * request a pointer to the data to be returned instead of handing 689 | * the function a location to put the data. This will allow the 690 | * async I/O to be performed and does not require any bcopy to be 691 | * done to put the data back into the location specified by the caller. 692 | ************************************************************************/ 693 | #ifdef HAVE_ANSIC_C 694 | int 695 | async_read_no_copy(struct cache *gc, long long fd, char **ubuffer, off64_t offset, long long size, long long stride, off64_t max, long long depth) 696 | #else 697 | int 698 | async_read_no_copy(gc, fd, ubuffer, offset, size, stride, max, depth) 699 | struct cache *gc; 700 | long long fd; 701 | char **ubuffer; 702 | off64_t offset; 703 | long long size; 704 | long long stride; 705 | off64_t max; 706 | long long depth; 707 | #endif 708 | { 709 | off64_t a_offset,r_offset; 710 | long long a_size; 711 | struct cache_ent *ce,*first_ce=0; 712 | long long i; 713 | ssize_t retval=0; 714 | ssize_t ret; 715 | long long del_read=0; 716 | long long start=0; 717 | 718 | a_offset=offset; 719 | a_size = size; 720 | /* 721 | * Check to see if it can be completed from the cache 722 | */ 723 | if((ce=(struct cache_ent *)incache(gc,fd,offset,size))) 724 | { 725 | while((ret=aio_error(&ce->myaiocb))== EINPROGRESS) 726 | { 727 | async_suspend(ce); 728 | } 729 | if(ret) 730 | printf("aio_error 3: ret %zd %d\n",ret,errno); 731 | printf("It changed in flight\n"); 732 | 733 | retval=aio_return(&ce->myaiocb); 734 | if(retval > 0) 735 | { 736 | *ubuffer= (char *)ce->myaiocb.aio_buf; 737 | }else 738 | *ubuffer= NULL; 739 | if(retval < ce->myaiocb.aio_nbytes) 740 | { 741 | printf("aio_return error4: ret %zd %d\n",retval,errno); 742 | printf("aio_return error4: fd %d offset %lld buffer %p size %zd Opcode %d\n", 743 | ce->myaiocb.aio_fildes, 744 | (long long)ce->myaiocb.aio_offset, 745 | ce->myaiocb.aio_buf, 746 | ce->myaiocb.aio_nbytes, 747 | ce->myaiocb.aio_lio_opcode 748 | ); 749 | } 750 | ce->direct=1; 751 | takeoff_cache(gc,ce); /* do not delete buffer*/ 752 | putoninuse(gc,ce); 753 | }else 754 | { 755 | /* 756 | * Clear the cache and issue the first request async() 757 | */ 758 | del_cache(gc); 759 | del_read++; 760 | first_ce=alloc_cache(gc,fd,offset,size,(long long)LIO_READ); /* allocate buffer */ 761 | /*printf("allocated buffer/read %x offset %d\n",first_ce->myaiocb.aio_buf,offset);*/ 762 | again: 763 | first_ce->oldbuf=first_ce->myaiocb.aio_buf; 764 | first_ce->oldfd=first_ce->myaiocb.aio_fildes; 765 | first_ce->oldsize=first_ce->myaiocb.aio_nbytes; 766 | ret=aio_read(&first_ce->myaiocb); 767 | if(ret!=0) 768 | { 769 | if(errno==EAGAIN) 770 | goto again; 771 | else 772 | printf("error returned from aio_read(). Ret %zd errno %d\n",ret,errno); 773 | } 774 | } 775 | if(stride==0) /* User does not want read-ahead */ 776 | goto out; 777 | if(a_offset<0) /* Before beginning of file */ 778 | goto out; 779 | if(a_offset+size>max) /* After end of file */ 780 | goto out; 781 | if(depth >=(max_depth-1)) 782 | depth=max_depth-1; 783 | if(depth==0) 784 | goto out; 785 | if(gc->count > 1) 786 | start=depth-1; 787 | for(i=start;i max) 793 | continue; 794 | if((ce=incache(gc,fd,r_offset,a_size))) 795 | continue; 796 | ce=alloc_cache(gc,fd,r_offset,a_size,(long long)LIO_READ); 797 | ce->oldbuf=ce->myaiocb.aio_buf; 798 | ce->oldfd=ce->myaiocb.aio_fildes; 799 | ce->oldsize=ce->myaiocb.aio_nbytes; 800 | ret=aio_read(&ce->myaiocb); 801 | if(ret!=0) 802 | { 803 | takeoff_cache(gc,ce); 804 | break; 805 | } 806 | } 807 | out: 808 | if(del_read) /* Wait for the first read to complete */ 809 | { 810 | while((ret=aio_error(&first_ce->myaiocb))== EINPROGRESS) 811 | { 812 | async_suspend(first_ce); 813 | } 814 | if(ret) 815 | printf("aio_error 4: ret %zd %d\n",ret,errno); 816 | if(first_ce->oldbuf != first_ce->myaiocb.aio_buf || 817 | first_ce->oldfd != first_ce->myaiocb.aio_fildes || 818 | first_ce->oldsize != first_ce->myaiocb.aio_nbytes) 819 | printf("It changed in flight2\n"); 820 | retval=aio_return(&first_ce->myaiocb); 821 | if(retval < first_ce->myaiocb.aio_nbytes) 822 | { 823 | printf("aio_return error5: ret %zd %d\n",retval,errno); 824 | printf("aio_return error5: fd %d offset %lld buffer %p size %zd Opcode %d\n", 825 | first_ce->myaiocb.aio_fildes, 826 | (long long)first_ce->myaiocb.aio_offset, 827 | first_ce->myaiocb.aio_buf, 828 | first_ce->myaiocb.aio_nbytes, 829 | first_ce->myaiocb.aio_lio_opcode 830 | ); 831 | } 832 | if(retval > 0) 833 | { 834 | *ubuffer= (char *)first_ce->myaiocb.aio_buf; 835 | }else 836 | *ubuffer= NULL; 837 | first_ce->direct=1; /* do not delete the buffer */ 838 | takeoff_cache(gc,first_ce); 839 | putoninuse(gc,first_ce); 840 | } 841 | return((int)retval); 842 | } 843 | 844 | /************************************************************************ 845 | * The caller is now finished with the data that was provided so 846 | * the library is now free to return the memory to the pool for later 847 | * reuse. 848 | ************************************************************************/ 849 | #ifdef HAVE_ANSIC_C 850 | void async_release(struct cache *gc) 851 | #else 852 | void 853 | async_release(gc) 854 | struct cache *gc; 855 | #endif 856 | { 857 | takeoffinuse(gc); 858 | } 859 | 860 | 861 | /************************************************************************ 862 | * Put the buffer on the inuse list. When the user is finished with 863 | * the buffer it will call back into async_release and the items on the 864 | * inuse list will be deallocated. 865 | ************************************************************************/ 866 | #ifdef HAVE_ANSIC_C 867 | void 868 | putoninuse(struct cache *gc,struct cache_ent *entry) 869 | #else 870 | void 871 | putoninuse(gc,entry) 872 | struct cache *gc; 873 | struct cache_ent *entry; 874 | #endif 875 | { 876 | if(gc->inuse_head) 877 | entry->forward=gc->inuse_head; 878 | else 879 | entry->forward=0; 880 | gc->inuse_head=entry; 881 | } 882 | 883 | /************************************************************************ 884 | * This is called when the application is finished with the data that 885 | * was provided. The memory may now be returned to the pool. 886 | ************************************************************************/ 887 | #ifdef HAVE_ANSIC_C 888 | void 889 | takeoffinuse(struct cache *gc) 890 | #else 891 | void 892 | takeoffinuse(gc) 893 | struct cache *gc; 894 | #endif 895 | { 896 | struct cache_ent *ce; 897 | if(gc->inuse_head==0) 898 | printf("Takeoffinuse error\n"); 899 | ce=gc->inuse_head; 900 | gc->inuse_head=gc->inuse_head->forward; 901 | 902 | if(gc->inuse_head !=0) 903 | printf("Error in take off inuse\n"); 904 | free((void*)(ce->real_address)); 905 | free(ce); 906 | } 907 | 908 | /************************************************************************* 909 | * This routine is a generic async writer assist funtion. It takes 910 | * the same calling parameters as write() but also extends the 911 | * interface to include: 912 | * 913 | * offset ..... offset in the file. 914 | * depth ..... How much read-ahead do you want. 915 | * 916 | *************************************************************************/ 917 | #ifdef HAVE_ANSIC_C 918 | size_t 919 | async_write(struct cache *gc,long long fd,char *buffer,long long size,off64_t offset,long long depth) 920 | #else 921 | size_t 922 | async_write(gc,fd,buffer,size,offset,depth) 923 | struct cache *gc; 924 | long long fd,size; 925 | char *buffer; 926 | off64_t offset; 927 | long long depth; 928 | #endif 929 | { 930 | struct cache_ent *ce; 931 | size_t ret; 932 | ce=allocate_write_buffer(gc,fd,offset,size,(long long)LIO_WRITE,depth,0LL,(char *)0,(char *)0); 933 | ce->direct=0; /* not direct. Lib supplies buffer and must free it */ 934 | mbcopy(buffer,(char *)(ce->myaiocb.aio_buf),(size_t)size); 935 | async_put_on_write_queue(gc,ce); 936 | /* 937 | printf("asw: fd %d offset %lld, size %zd\n",ce->myaiocb.aio_fildes, 938 | ce->myaiocb.aio_offset, 939 | ce->myaiocb.aio_nbytes); 940 | */ 941 | 942 | again: 943 | ret=aio_write(&ce->myaiocb); 944 | if(ret==-1) 945 | { 946 | if(errno==EAGAIN) 947 | { 948 | async_wait_for_write(gc); 949 | goto again; 950 | } 951 | if(errno==0) 952 | { 953 | /* Compensate for bug in async library */ 954 | async_wait_for_write(gc); 955 | goto again; 956 | } 957 | else 958 | { 959 | printf("Error in aio_write: ret %zd errno %d count %lld\n",ret,errno,gc->w_count); 960 | /* 961 | printf("aio_write_no_copy: fd %d buffer %x offset %lld size %zd\n", 962 | ce->myaiocb.aio_fildes, 963 | ce->myaiocb.aio_buf, 964 | ce->myaiocb.aio_offset, 965 | ce->myaiocb.aio_nbytes); 966 | */ 967 | exit(177); 968 | } 969 | } 970 | return((ssize_t)size); 971 | } 972 | 973 | /************************************************************************* 974 | * Allocate a write aiocb and write buffer of the size specified. Also 975 | * put some extra buffer padding so that VX_DIRECT can do its job when 976 | * needed. 977 | *************************************************************************/ 978 | 979 | #ifdef HAVE_ANSIC_C 980 | struct cache_ent * 981 | allocate_write_buffer( struct cache *gc, long long fd, long long size,long long op, 982 | off64_t offset, long long w_depth, long long direct, char *buffer, char *free_addr) 983 | #else 984 | struct cache_ent * 985 | allocate_write_buffer(gc,fd,offset,size,op,w_depth,direct,buffer,free_addr) 986 | struct cache *gc; 987 | long long fd,size,op; 988 | off64_t offset; 989 | long long w_depth; 990 | long long direct; 991 | char *buffer,*free_addr; 992 | #endif 993 | { 994 | struct cache_ent *ce; 995 | intptr_t temp; 996 | if(fd==0LL) 997 | { 998 | printf("Setting up write buffer insane\n"); 999 | exit(178); 1000 | } 1001 | if(gc->w_count > w_depth) 1002 | async_wait_for_write(gc); 1003 | ce=(struct cache_ent *)malloc((size_t)sizeof(struct cache_ent)); 1004 | if(ce == (struct cache_ent *)0) 1005 | { 1006 | printf("Malloc failed 1\n"); 1007 | exit(179); 1008 | } 1009 | bzero(ce,sizeof(struct cache_ent)); 1010 | ce->myaiocb.aio_fildes=(int)fd; 1011 | ce->myaiocb.aio_offset=(off_t)offset; 1012 | if(!direct) 1013 | { 1014 | ce->real_address = malloc((size_t)(size+page_size)); 1015 | temp = (intptr_t)ce->real_address; 1016 | temp = (temp+page_size) & ~(page_size-1); 1017 | ce->myaiocb.aio_buf=(volatile void *)temp; 1018 | } 1019 | else 1020 | { 1021 | ce->myaiocb.aio_buf=(volatile void *)buffer; 1022 | ce->real_address=(char *)free_addr; 1023 | } 1024 | if(ce->myaiocb.aio_buf == 0) 1025 | { 1026 | printf("Malloc failed 2\n"); 1027 | exit(180); 1028 | } 1029 | ce->myaiocb.aio_reqprio=0; 1030 | ce->myaiocb.aio_nbytes=(size_t)size; 1031 | ce->myaiocb.aio_sigevent.sigev_notify=SIGEV_NONE; 1032 | ce->myaiocb.aio_lio_opcode=(int)op; 1033 | ce->fd=(int)fd; 1034 | return(ce); 1035 | } 1036 | 1037 | /************************************************************************* 1038 | * Put it on the outbound queue. 1039 | *************************************************************************/ 1040 | 1041 | #ifdef HAVE_ANSIC_C 1042 | void 1043 | async_put_on_write_queue(struct cache *gc,struct cache_ent *ce) 1044 | #else 1045 | void 1046 | async_put_on_write_queue(gc,ce) 1047 | struct cache *gc; 1048 | struct cache_ent *ce; 1049 | #endif 1050 | { 1051 | ce->forward=0; 1052 | ce->back=gc->w_tail; 1053 | if(gc->w_tail) 1054 | gc->w_tail->forward = ce; 1055 | gc->w_tail= ce; 1056 | if(!gc->w_head) 1057 | gc->w_head=ce; 1058 | gc->w_count++; 1059 | return; 1060 | } 1061 | 1062 | /************************************************************************* 1063 | * Cleanup all outstanding writes 1064 | *************************************************************************/ 1065 | #ifdef HAVE_AHSIC_C 1066 | void 1067 | async_write_finish(struct cache *gc) 1068 | #else 1069 | void 1070 | async_write_finish(gc) 1071 | struct cache *gc; 1072 | #endif 1073 | { 1074 | while(gc->w_head) 1075 | { 1076 | /*printf("async_write_finish: Waiting for buffer %x to finish\n",gc->w_head->myaiocb.aio_buf);*/ 1077 | async_wait_for_write(gc); 1078 | } 1079 | } 1080 | 1081 | /************************************************************************* 1082 | * Wait for an I/O to finish 1083 | *************************************************************************/ 1084 | 1085 | #ifdef HAVE_ANSIC_C 1086 | void 1087 | async_wait_for_write(struct cache *gc) 1088 | #else 1089 | void 1090 | async_wait_for_write(gc) 1091 | struct cache *gc; 1092 | #endif 1093 | { 1094 | struct cache_ent *ce; 1095 | size_t ret; 1096 | int retval; 1097 | if(gc->w_head==0) 1098 | return; 1099 | ce=gc->w_head; 1100 | gc->w_head=ce->forward; 1101 | gc->w_count--; 1102 | ce->forward=0; 1103 | if(ce==gc->w_tail) 1104 | gc->w_tail=0; 1105 | /*printf("Wait for buffer %x offset %lld size %zd to finish\n", 1106 | ce->myaiocb.aio_buf, 1107 | ce->myaiocb.aio_offset, 1108 | ce->myaiocb.aio_nbytes); 1109 | printf("write count %lld \n",gc->w_count); 1110 | */ 1111 | while((ret=aio_error(&ce->myaiocb))== EINPROGRESS) 1112 | { 1113 | async_suspend(ce); 1114 | } 1115 | if(ret) 1116 | { 1117 | printf("aio_error 5: ret %zd %d\n",ret,errno); 1118 | printf("fd %d offset %lld size %zd\n", 1119 | ce->myaiocb.aio_fildes, 1120 | (long long)ce->myaiocb.aio_offset, 1121 | ce->myaiocb.aio_nbytes); 1122 | exit(181); 1123 | } 1124 | 1125 | retval=aio_return(&ce->myaiocb); 1126 | if(retval < 0) 1127 | { 1128 | printf("aio_return error: %d\n",errno); 1129 | } 1130 | 1131 | if(!ce->direct) 1132 | { 1133 | /* printf("Freeing buffer %x\n",ce->real_address);*/ 1134 | free((void *)(ce->real_address)); 1135 | free((void *)ce); 1136 | } 1137 | 1138 | } 1139 | 1140 | /************************************************************************* 1141 | * This routine is a generic async writer assist funtion. It takes 1142 | * the same calling parameters as write() but also extends the 1143 | * interface to include: 1144 | * 1145 | * offset ..... offset in the file. 1146 | * depth ..... How much read-ahead do you want. 1147 | * free_addr .. address of memory to free after write is completed. 1148 | * 1149 | *************************************************************************/ 1150 | #ifdef HAVE_ANSIC_C 1151 | size_t 1152 | async_write_no_copy(struct cache *gc,long long fd,char *buffer,long long size,off64_t offset,long long depth,char *free_addr) 1153 | #else 1154 | size_t 1155 | async_write_no_copy(gc,fd,buffer,size,offset,depth,free_addr) 1156 | struct cache *gc; 1157 | long long fd,size; 1158 | char *buffer; 1159 | off64_t offset; 1160 | long long depth; 1161 | char *free_addr; 1162 | #endif 1163 | { 1164 | struct cache_ent *ce; 1165 | size_t ret; 1166 | long long direct = 1; 1167 | ce=allocate_write_buffer(gc,fd,offset,size,(long long)LIO_WRITE,depth,direct,buffer,free_addr); 1168 | ce->direct=0; /* have library de-allocate the buffer */ 1169 | async_put_on_write_queue(gc,ce); 1170 | /* 1171 | printf("awnc: fd %d offset %lld, size %zd\n",ce->myaiocb.aio_fildes, 1172 | ce->myaiocb.aio_offset, 1173 | ce->myaiocb.aio_nbytes); 1174 | */ 1175 | 1176 | again: 1177 | ret=aio_write(&ce->myaiocb); 1178 | if(ret==-1) 1179 | { 1180 | if(errno==EAGAIN) 1181 | { 1182 | async_wait_for_write(gc); 1183 | goto again; 1184 | } 1185 | if(errno==0) 1186 | { 1187 | /* Compensate for bug in async library */ 1188 | async_wait_for_write(gc); 1189 | goto again; 1190 | } 1191 | else 1192 | { 1193 | printf("Error in aio_write: ret %zd errno %d\n",ret,errno); 1194 | printf("aio_write_no_copy: fd %d buffer %p offset %lld size %zd\n", 1195 | ce->myaiocb.aio_fildes, 1196 | ce->myaiocb.aio_buf, 1197 | (long long)ce->myaiocb.aio_offset, 1198 | ce->myaiocb.aio_nbytes); 1199 | exit(182); 1200 | } 1201 | } 1202 | else 1203 | { 1204 | return((ssize_t)size); 1205 | } 1206 | } 1207 | 1208 | void mbcopy(source, dest, len) 1209 | const char *source; 1210 | char *dest; 1211 | size_t len; 1212 | { 1213 | int i; 1214 | for(i=0;i 16 | #endif 17 | #include 18 | #include 19 | #include 20 | #if defined(__AIX__) || defined(__FreeBSD__) || defined(__DragonFly__) 21 | #include 22 | #else 23 | #include 24 | #endif 25 | 26 | #if defined(OSV5) || defined(linux) || defined (__FreeBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__APPLE__) || defined(__DragonFly__) || defined(__NetBSD__) 27 | #include 28 | #endif 29 | 30 | #if defined(linux) || defined(__DragonFly__) || defined(IOZ_macosx) || defined(__NetBSD__) 31 | #include 32 | #include 33 | #endif 34 | 35 | #if (defined(solaris) && defined( __LP64__ )) || defined(__s390x__) || defined(__FreeBSD__) 36 | /* If we are building for 64-bit Solaris, all functions that return pointers 37 | * must be declared before they are used; otherwise the compiler will assume 38 | * that they return ints and the top 32 bits of the pointer will be lost, 39 | * causing segmentation faults. The following includes take care of this. 40 | * It should be safe to add these for all other OSs too, but we're only 41 | * doing it for Solaris now in case another OS turns out to be a special case. 42 | */ 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #endif 49 | /* Little Endian */ 50 | #define ENDIAN_1 1 51 | /* Big Endian */ 52 | #define ENDIAN_2 2 53 | /* Middle Endian */ 54 | #define ENDIAN_3 3 55 | /* Middle Endian */ 56 | #define ENDIAN_4 4 57 | 58 | int junk, *junkp; 59 | 60 | 61 | #ifdef HAVE_ANSIC_C 62 | /************************************************************************/ 63 | /* Here is the API... Enjoy */ 64 | /************************************************************************/ 65 | /* Create worksheet */ 66 | int create_xls(char *); 67 | /* Args: Filename */ 68 | /* */ 69 | /* Close worksheet */ 70 | void close_xls(int); 71 | /* Args: file descriptor */ 72 | /* */ 73 | /* Put a 16 bit integer in worksheet */ 74 | void do_int(int,int,int,int); 75 | /* Args: file descriptor, */ 76 | /* value, */ 77 | /* row, */ 78 | /* column */ 79 | 80 | /* Put a double in 8 byte float */ 81 | void do_float(int,double,int,int); 82 | /* Args: file descriptor, */ 83 | /* value, */ 84 | /* row, */ 85 | /* column */ 86 | /* Put a string in worksheet */ 87 | void do_label(int,char *,int,int); 88 | /* Args: file descriptor, */ 89 | /* string, */ 90 | /* row, */ 91 | /* column */ 92 | /************************************************************************/ 93 | 94 | char libbif_version[] = "Libbif Version $Revision: 3.30 $"; 95 | #endif 96 | 97 | #define BOF 0x9 98 | #define INTEGER 0x2 99 | #define FLOAT 0x3 100 | #define LABEL 0x4 101 | #define EXCEL_VERS 0x2 102 | #define WORKSHEET 0x10 103 | 104 | struct bof_record{ /* Beginning of file */ 105 | char hi_opcode; 106 | char lo_opcode; 107 | char hi_length; 108 | char lo_length; 109 | char hi_version; /* Excel version */ 110 | char lo_version; 111 | char hi_filetype; 112 | char lo_filetype; 113 | }; 114 | struct int_record { 115 | char hi_opcode; /* Type 2 of record */ 116 | char lo_opcode; 117 | char hi_length; 118 | char lo_length; 119 | char hi_row; 120 | char lo_row; 121 | char hi_column; 122 | char lo_column; 123 | char rgbhi; 124 | char rgbmed; 125 | char rgblo; 126 | char hi_data; 127 | char lo_data; 128 | }; 129 | struct label_record { 130 | char hi_opcode; /* Type 4 of record */ 131 | char lo_opcode; 132 | char hi_length; 133 | char lo_length; 134 | char hi_row; 135 | char lo_row; 136 | char hi_column; 137 | char lo_column; 138 | char rgbhi; 139 | char rgbmed; 140 | char rgblo; 141 | char string_length; 142 | char str_array[256]; 143 | }; 144 | struct float_record { /* Type 3 record */ 145 | char hi_opcode; 146 | char lo_opcode; 147 | char hi_length; 148 | char lo_length; 149 | char hi_row; 150 | char lo_row; 151 | char hi_column; 152 | char lo_column; 153 | char rgbhi; 154 | char rgbmed; 155 | char rgblo; 156 | double data; 157 | }; 158 | 159 | #ifdef HAVE_ANSIC_C 160 | void close_xls(int); 161 | int create_xls(char *); 162 | void do_header(int); 163 | void do_int(int, int, int, int); 164 | void do_float(int, double, int, int); 165 | void do_label(int, char *, int, int ); 166 | void do_eof(int) ; 167 | int endian(void); 168 | #else 169 | void 170 | close_xls(); 171 | int create_xls(); 172 | void do_header(); 173 | void do_int(); 174 | void do_float(); 175 | void do_label(); 176 | void do_eof(); 177 | int endian(); 178 | #endif 179 | 180 | /* 181 | * Write the EOF and close the file 182 | */ 183 | #ifdef HAVE_ANSIC_C 184 | void 185 | close_xls(int fd) 186 | { 187 | #else 188 | void 189 | close_xls(fd) 190 | int fd; 191 | { 192 | #endif 193 | do_eof(fd); 194 | close(fd); 195 | } 196 | 197 | /* 198 | * Create xls worksheet. Create file and put the BOF record in it. 199 | */ 200 | #ifdef HAVE_ANSIC_C 201 | int 202 | create_xls(char *name) 203 | { 204 | #else 205 | create_xls(name) 206 | char *name; 207 | { 208 | #endif 209 | int fd; 210 | unlink(name); 211 | #ifdef Windows 212 | fd=open(name,O_BINARY|O_CREAT|O_RDWR,0666); 213 | #else 214 | fd=open(name,O_CREAT|O_RDWR,0666); 215 | #endif 216 | if(fd<0) 217 | { 218 | printf("Error opening file %s\n",name); 219 | exit(-1); 220 | } 221 | do_header(fd); 222 | return(fd); 223 | } 224 | 225 | #ifdef HAVE_ANSIC_C 226 | void 227 | do_header(int fd) /* Stick the BOF at the beginning of the file */ 228 | { 229 | #else 230 | do_header(fd) 231 | int fd; 232 | { 233 | #endif 234 | struct bof_record bof; 235 | bof.hi_opcode=BOF; 236 | bof.lo_opcode = 0x0; 237 | bof.hi_length=0x4; 238 | bof.lo_length=0x0; 239 | bof.hi_version=EXCEL_VERS; 240 | bof.lo_version=0x0; 241 | bof.hi_filetype=WORKSHEET; 242 | bof.lo_filetype=0x0; 243 | junk=write(fd,&bof,sizeof(struct bof_record)); 244 | } 245 | 246 | /* 247 | * Put an integer (16 bit) in the worksheet 248 | */ 249 | #ifdef HAVE_ANSIC_C 250 | void 251 | do_int(int fd,int val, int row, int column) 252 | { 253 | #else 254 | do_int(fd,val,row,column) 255 | int fd,val,row,column; 256 | { 257 | #endif 258 | struct int_record intrec; 259 | short s_row,s_column; 260 | s_row=(short)row; 261 | s_column=(short)column; 262 | intrec.hi_opcode=INTEGER; 263 | intrec.lo_opcode=0x00; 264 | intrec.hi_length=0x09; 265 | intrec.lo_length=0x00; 266 | intrec.rgbhi=0x0; 267 | intrec.rgbmed=0x0; 268 | intrec.rgblo=0x0; 269 | intrec.hi_row=(char)s_row&0xff; 270 | intrec.lo_row=(char)(s_row>>8)&0xff; 271 | intrec.hi_column=(char)(s_column&0xff); 272 | intrec.lo_column=(char)(s_column>>8)&0xff; 273 | intrec.hi_data=(val & 0xff); 274 | intrec.lo_data=(val & 0xff00)>>8; 275 | junk=write(fd,&intrec,13); 276 | } 277 | 278 | /* Note: This routine converts Big Endian to Little Endian 279 | * and writes the record out. 280 | */ 281 | 282 | /* 283 | * Put a double in the worksheet as 8 byte float in IEEE format. 284 | */ 285 | #ifdef HAVE_ANSIC_C 286 | void 287 | do_float(int fd, double value, int row, int column) 288 | { 289 | #else 290 | do_float(fd, value, row, column) 291 | int fd; 292 | double value; 293 | int row,column; 294 | { 295 | #endif 296 | struct float_record floatrec; 297 | short s_row,s_column; 298 | unsigned char *sptr,*dptr; 299 | s_row=(short)row; 300 | s_column=(short)column; 301 | floatrec.hi_opcode=FLOAT; 302 | floatrec.lo_opcode=0x00; 303 | floatrec.hi_length=0xf; 304 | floatrec.lo_length=0x00; 305 | floatrec.rgbhi=0x0; 306 | floatrec.rgbmed=0x0; 307 | floatrec.rgblo=0x0; 308 | floatrec.hi_row=(char)(s_row&0xff); 309 | floatrec.lo_row=(char)((s_row>>8)&0xff); 310 | floatrec.hi_column=(char)(s_column&0xff); 311 | floatrec.lo_column=(char)((s_column>>8)&0xff); 312 | sptr =(unsigned char *) &value; 313 | dptr =(unsigned char *) &floatrec.data; 314 | 315 | if(endian()==ENDIAN_2) /* Big Endian */ 316 | { 317 | dptr[0]=sptr[7]; /* Convert to Little Endian */ 318 | dptr[1]=sptr[6]; 319 | dptr[2]=sptr[5]; 320 | dptr[3]=sptr[4]; 321 | dptr[4]=sptr[3]; 322 | dptr[5]=sptr[2]; 323 | dptr[6]=sptr[1]; 324 | dptr[7]=sptr[0]; 325 | } 326 | if(endian()==ENDIAN_3) /* Middle Endian */ 327 | { 328 | dptr[0]=sptr[4]; /* 16 bit swapped ARM */ 329 | dptr[1]=sptr[5]; 330 | dptr[2]=sptr[6]; 331 | dptr[3]=sptr[7]; 332 | dptr[4]=sptr[0]; 333 | dptr[5]=sptr[1]; 334 | dptr[6]=sptr[2]; 335 | dptr[7]=sptr[3]; 336 | } 337 | 338 | if(endian()==ENDIAN_1) /* Little Endian */ 339 | { 340 | dptr[0]=sptr[0]; /* Do not convert to Little Endian */ 341 | dptr[1]=sptr[1]; 342 | dptr[2]=sptr[2]; 343 | dptr[3]=sptr[3]; 344 | dptr[4]=sptr[4]; 345 | dptr[5]=sptr[5]; 346 | dptr[6]=sptr[6]; 347 | dptr[7]=sptr[7]; 348 | } 349 | if(endian()==-1) /* Unsupported architecture */ 350 | { 351 | dptr[0]=0; 352 | dptr[1]=0; 353 | dptr[2]=0; 354 | dptr[3]=0; 355 | dptr[4]=0; 356 | dptr[5]=0; 357 | dptr[6]=0; 358 | dptr[7]=0; 359 | printf("Excel output not supported on this architecture.\n"); 360 | } 361 | junk=write(fd,&floatrec,11); /* Don't write floatrec. Padding problems */ 362 | junk=write(fd,&floatrec.data,8); /* Write value seperately */ 363 | } 364 | 365 | /* 366 | * Put a string as a label in the worksheet. 367 | */ 368 | #ifdef HAVE_ANSIC_C 369 | void 370 | do_label(int fd, char *string, int row, int column) 371 | { 372 | #else 373 | do_label(fd, string, row, column) 374 | int fd; 375 | char *string; 376 | int row,column; 377 | { 378 | #endif 379 | struct label_record labelrec; 380 | short s_row,s_column; 381 | int i; 382 | for(i=0;i<255;i++) 383 | labelrec.str_array[i]=0; 384 | s_row=(short)row; 385 | s_column=(short)column; 386 | i=strlen(string); 387 | labelrec.hi_opcode=LABEL; 388 | labelrec.lo_opcode=0x00; 389 | labelrec.hi_length=0x08; /* 264 total bytes */ 390 | labelrec.lo_length=0x01; 391 | labelrec.rgblo=0x0; 392 | labelrec.rgbmed=0x0; 393 | labelrec.rgbhi=0x0; 394 | labelrec.hi_row=(char)(s_row&0xff); 395 | labelrec.lo_row=(char)((s_row>>8)&0xff); 396 | labelrec.hi_column=(char)(s_column&0xff); 397 | labelrec.lo_column=(char)((s_column>>8)&0xff); 398 | labelrec.string_length=i; 399 | if(i > 255) /* If too long then terminate it early */ 400 | string[254]=0; 401 | i=strlen(string); 402 | strcpy(labelrec.str_array,string); 403 | 404 | junk=write(fd,&labelrec,sizeof(struct label_record)); 405 | 406 | } 407 | 408 | /* 409 | * Write the EOF in the file 410 | */ 411 | #ifdef HAVE_ANSIC_C 412 | void 413 | do_eof(int fd) 414 | { 415 | #else 416 | do_eof(fd) 417 | int fd; 418 | { 419 | #endif 420 | char buf[]={0x0a,0x00,0x00,0x00}; 421 | junk=write(fd,buf,4); 422 | } 423 | 424 | /* 425 | * Routine to determine the Endian-ness of the system. This 426 | * is needed for Iozone to convert doubles (floats) into 427 | * Little-endian format. This is needed for Excel to be 428 | * able to interpret the file 429 | */ 430 | int 431 | endian(void) 432 | { 433 | long long foo = 0x0102030405060708LL; 434 | long foo1 = 0x012345678; 435 | unsigned char *c,c1,c2,c3,c4,c5,c6,c7,c8; 436 | c=(unsigned char *)&foo; 437 | c1=*c++; 438 | c2=*c++; 439 | c3=*c++; 440 | c4=*c++; 441 | c5=*c++; 442 | c6=*c++; 443 | c7=*c++; 444 | c8=*c; 445 | 446 | /*--------------------------------------------------------------*/ 447 | /* printf("%x %x %x %x %x %x %x %x\n",c1,c2,c3,c4,c5,c6,c7,c8); */ 448 | /*--------------------------------------------------------------*/ 449 | 450 | /* Little Endian format ? ( Intel ) */ 451 | if( (c1==0x08) && (c2==0x07) && (c3==0x06) && (c4==0x05) && 452 | (c5==0x04) && (c6==0x03) && (c7==0x02) && (c8==0x01) ) 453 | return(ENDIAN_1); 454 | /* Big Endian format ? ( Sparc, Risc... */ 455 | if( (c1==0x01) && (c2==0x02) && (c3==0x03) && (c4==0x04) && 456 | (c5==0x05) && (c6==0x06) && (c7==0x07) && (c8==0x08) ) 457 | return(ENDIAN_2); 458 | /* Middle Endian format ? ( ARM ... ) */ 459 | if( (c1==0x04) && (c2==0x03) && (c3==0x02) && (c4==0x01) && 460 | (c5==0x08) && (c6==0x07) && (c7==0x06) && (c8==0x05) ) 461 | return(ENDIAN_3); 462 | c=(unsigned char *)&foo1; 463 | c1=*c++; 464 | c2=*c++; 465 | c3=*c++; 466 | c4=*c++; 467 | /* Another middle endian format ? ( PDP-11 ... ) */ 468 | if( (c1==0x34) && (c2==0x12) && (c3==0x78) && (c4==0x56)) 469 | return(ENDIAN_4); 470 | 471 | return(-1); 472 | } 473 | -------------------------------------------------------------------------------- /tests/60-iozone/pit_server.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * File: pit_server.c 3 | * 4 | * Description: Contains source code for an IPv6-capable 'PIT' server. 5 | * This is a derivative of the tod6 (time-of-day) server that was written 6 | * by John Wenker. 7 | * ....... 8 | * Author of tod6: John Wenker, Sr. Software Engineer, 9 | * Performance Technologies, San Diego, USA 10 | * ....... 11 | * The program tod6 was a time of day server. It has beeen modified 12 | * to provide a microsecond timestamp on request. Modified and adapted 13 | * for PIT purposes by Don Capps. [ capps@iozone.org ] 14 | * 15 | * This server sends the current value of gettimeofday() in 16 | * microseconds back to the client, as a numerical string. 17 | * 18 | * /etc/services should contain "PIT" with a specified port value. 19 | * 20 | ******************************************************************************/ 21 | /* 22 | ** System header files. 23 | */ 24 | #include /* errno declaration & error codes. */ 25 | #include /* getaddrinfo(3) et al. */ 26 | #include /* sockaddr_in & sockaddr_in6 definition. */ 27 | #include /* printf(3) et al. */ 28 | #include /* exit(2). */ 29 | #include /* String manipulation & memory functions. */ 30 | #if defined(_SUA_) 31 | #include /* poll(2) and related definitions. */ 32 | #else 33 | #include /* poll(2) and related definitions. */ 34 | #endif 35 | #include /* Socket functions (socket(2), bind(2), etc). */ 36 | #include /* time(2) & ctime(3). */ 37 | #include /* gettimeofday */ 38 | #include /* getopt(3), read(2), etc. */ 39 | /* Include for Cygnus development environment for Windows */ 40 | #if defined (Windows) 41 | #include 42 | int errno; 43 | #endif 44 | 45 | #if defined(_SUA_) 46 | extern char *optarg, *opterr; 47 | #endif 48 | 49 | /* 50 | ** Constants. 51 | ** 52 | ** Please remember to add PIT service to the /etc/services file. 53 | */ 54 | #define DFLT_SERVICE "PIT" /* Programmable Interdimensional Timer */ 55 | 56 | #define INVALID_DESC -1 /* Invalid file descriptor. */ 57 | #define MAXCONNQLEN 3 /* Max nbr of connection requests to queue. */ 58 | #define MAXTCPSCKTS 2 /* One TCP socket for IPv4 & one for IPv6. */ 59 | #define MAXUDPSCKTS 2 /* One UDP socket for IPv4 & one for IPv6. */ 60 | #define VALIDOPTS "vh:p:" /* Valid command options. */ 61 | /* 62 | ** Simple boolean type definition. 63 | */ 64 | int false = 0; 65 | int true = 1; 66 | /* 67 | ** Prototypes for internal helper functions. 68 | */ 69 | static int openSckt( const char *service, 70 | const char *protocol, 71 | int desc[ ], 72 | size_t *descSize ); 73 | static void pit( int tSckt[ ], 74 | size_t tScktSize, 75 | int uSckt[ ], 76 | size_t uScktSize ); 77 | /* 78 | ** Global data objects. 79 | */ 80 | static char hostBfr[ NI_MAXHOST ]; /* For use w/getnameinfo(3). */ 81 | static const char *pgmName; /* Program name w/o dir prefix. */ 82 | static char servBfr[ NI_MAXSERV ]; /* For use w/getnameinfo(3). */ 83 | static int verbose = 0; /* Verbose mode indication. */ 84 | struct timeval tm; /* Timeval structure, used with gettimeofday() */ 85 | char timeStr[40]; /* String for time in microseconds */ 86 | char service_name[20]; 87 | int need; 88 | /* 89 | ** Usage macro for command syntax violations. 90 | */ 91 | #define USAGE \ 92 | { \ 93 | fprintf( stderr, \ 94 | "Usage: %s [-v] -p service \n", \ 95 | pgmName ); \ 96 | exit( 127 ); \ 97 | } /* End USAGE macro. */ 98 | /* 99 | ** Macro to terminate the program if a system call error occurs. The system 100 | ** call must be one of the usual type that returns -1 on error. 101 | */ 102 | #define CHK(expr) \ 103 | do \ 104 | { \ 105 | if ( (expr) == -1 ) \ 106 | { \ 107 | fprintf( stderr, \ 108 | "%s (line %d): System call ERROR - %s.\n", \ 109 | pgmName, \ 110 | __LINE__, \ 111 | strerror( errno ) ); \ 112 | exit( 1 ); \ 113 | } /* End IF system call failed. */ \ 114 | } while ( false ) 115 | /****************************************************************************** 116 | * Function: main 117 | * 118 | * Description: 119 | * Set up a PIT server and handle network requests. This server 120 | * handles both TCP and UDP requests. 121 | * 122 | * Parameters: 123 | * The usual argc and argv parameters to a main() function. 124 | * 125 | * Return Value: 126 | * This is a daemon program and never returns. However, in the degenerate 127 | * case where no sockets are created, the function returns zero. 128 | ******************************************************************************/ 129 | int main( int argc, 130 | char *argv[ ] ) 131 | { 132 | int opt; 133 | int tSckt[ MAXTCPSCKTS ]; /* Array of TCP socket descriptors. */ 134 | size_t tScktSize = MAXTCPSCKTS; /* Size of uSckt (# of elements). */ 135 | int uSckt[ MAXUDPSCKTS ]; /* Array of UDP socket descriptors. */ 136 | size_t uScktSize = MAXUDPSCKTS; /* Size of uSckt (# of elements). */ 137 | 138 | strcpy(service_name,DFLT_SERVICE); 139 | /* 140 | ** Set the program name (w/o directory prefix). 141 | */ 142 | pgmName = strrchr( argv[ 0 ], '/' ); 143 | pgmName = pgmName == NULL ? argv[ 0 ] : pgmName + 1; 144 | /* 145 | ** Process command options. 146 | */ 147 | opterr = 0; /* Turns off "invalid option" error messages. */ 148 | while ( ( opt = getopt( argc, argv, VALIDOPTS ) ) >= 0 ) 149 | { 150 | switch ( opt ) 151 | { 152 | case 'v': /* Verbose mode. */ 153 | { 154 | verbose = true; 155 | break; 156 | } 157 | case 'p': /* Get the port number */ 158 | { 159 | strcpy(service_name,optarg); 160 | need++; 161 | break; 162 | } 163 | default: 164 | { 165 | USAGE; 166 | } 167 | } /* End SWITCH on command option. */ 168 | } /* End WHILE processing options. */ 169 | 170 | if(need < 1) 171 | { 172 | USAGE; 173 | } 174 | /* 175 | ** Open both a TCP and UDP socket, for both IPv4 & IPv6, on which to receive 176 | ** service requests. 177 | */ 178 | if ( ( openSckt( service_name, "tcp", tSckt, &tScktSize ) < 0 ) || 179 | ( openSckt( service_name, "udp", uSckt, &uScktSize ) < 0 ) ) 180 | { 181 | exit( 1 ); 182 | } 183 | /* 184 | ** Run the Programmable Interdimensional Timer server. 185 | */ 186 | if ( ( tScktSize > 0 ) || ( uScktSize > 0 ) ) 187 | { 188 | pit( tSckt, /* pit() never returns. */ 189 | tScktSize, 190 | uSckt, 191 | uScktSize ); 192 | } 193 | /* 194 | ** Since pit() never returns, execution only gets here if no sockets were 195 | ** created. 196 | */ 197 | if ( verbose ) 198 | { 199 | fprintf( stderr, 200 | "%s: No sockets opened... terminating.\n", 201 | pgmName ); 202 | } 203 | return 0; 204 | } /* End main() */ 205 | /****************************************************************************** 206 | * Function: openSckt 207 | * 208 | * Description: 209 | * Open passive (server) sockets for the indicated inet service & protocol. 210 | * Notice in the last sentence that "sockets" is plural. During the interim 211 | * transition period while everyone is switching over to IPv6, the server 212 | * application has to open two sockets on which to listen for connections... 213 | * one for IPv4 traffic and one for IPv6 traffic. 214 | * 215 | * Parameters: 216 | * service - Pointer to a character string representing the well-known port 217 | * on which to listen (can be a service name or a decimal number). 218 | * protocol - Pointer to a character string representing the transport layer 219 | * protocol (only "tcp" or "udp" are valid). 220 | * desc - Pointer to an array into which the socket descriptors are 221 | * placed when opened. 222 | * descSize - This is a value-result parameter. On input, it contains the 223 | * max number of descriptors that can be put into 'desc' (i.e. the 224 | * number of elements in the array). Upon return, it will contain 225 | * the number of descriptors actually opened. Any unused slots in 226 | * 'desc' are set to INVALID_DESC. 227 | * 228 | * Return Value: 229 | * 0 on success, -1 on error. 230 | ******************************************************************************/ 231 | static int openSckt( const char *service, 232 | const char *protocol, 233 | int desc[ ], 234 | size_t *descSize ) 235 | { 236 | struct addrinfo *ai; 237 | int aiErr; 238 | struct addrinfo *aiHead; 239 | struct addrinfo hints = { .ai_flags = AI_PASSIVE, /* Server mode. */ 240 | .ai_family = PF_UNSPEC }; /* IPv4 or IPv6. */ 241 | size_t maxDescs = *descSize; 242 | /* 243 | ** Initialize output parameters. When the loop completes, *descSize is 0. 244 | */ 245 | while ( *descSize > 0 ) 246 | { 247 | desc[ --( *descSize ) ] = INVALID_DESC; 248 | } 249 | /* 250 | ** Check which protocol is selected (only TCP and UDP are valid). 251 | */ 252 | if ( strcmp( protocol, "tcp" ) == 0 ) /* TCP protocol. */ 253 | { 254 | hints.ai_socktype = SOCK_STREAM; 255 | hints.ai_protocol = IPPROTO_TCP; 256 | } 257 | else if ( strcmp( protocol, "udp" ) == 0 ) /* UDP protocol. */ 258 | { 259 | hints.ai_socktype = SOCK_DGRAM; 260 | hints.ai_protocol = IPPROTO_UDP; 261 | } 262 | else /* Invalid protocol. */ 263 | { 264 | fprintf( stderr, 265 | "%s (line %d): ERROR - Unknown transport " 266 | "layer protocol \"%s\".\n", 267 | pgmName, 268 | __LINE__, 269 | protocol ); 270 | return -1; 271 | } 272 | /* 273 | ** Look up the service's "well-known" port number. Notice that NULL is being 274 | ** passed for the 'node' parameter, and that the AI_PASSIVE flag is set in 275 | ** 'hints'. Thus, the program is requesting passive address information. 276 | ** The network address is initialized to :: (all zeros) for IPv6 records, or 277 | ** 0.0.0.0 for IPv4 records. 278 | */ 279 | if ( ( aiErr = getaddrinfo( NULL, 280 | service, 281 | &hints, 282 | &aiHead ) ) != 0 ) 283 | { 284 | fprintf( stderr, 285 | "%s (line %d): ERROR - %s.\n", 286 | pgmName, 287 | __LINE__, 288 | gai_strerror( aiErr ) ); 289 | return -1; 290 | } 291 | /* 292 | ** For each of the address records returned, attempt to set up a passive 293 | ** socket. 294 | */ 295 | for ( ai = aiHead; 296 | ( ai != NULL ) && ( *descSize < maxDescs ); 297 | ai = ai->ai_next ) 298 | { 299 | if ( verbose ) 300 | { 301 | /* 302 | ** Display the current address info. Start with the protocol- 303 | ** independent fields first. 304 | */ 305 | fprintf( stderr, 306 | "Setting up a passive socket based on the " 307 | "following address info:\n" 308 | " ai_flags = 0x%02X\n" 309 | " ai_family = %d (PF_INET = %d, PF_INET6 = %d)\n" 310 | " ai_socktype = %d (SOCK_STREAM = %d, SOCK_DGRAM = %d)\n" 311 | " ai_protocol = %d (IPPROTO_TCP = %d, IPPROTO_UDP = %d)\n" 312 | " ai_addrlen = %d (sockaddr_in = %zu, " 313 | "sockaddr_in6 = %zu)\n", 314 | ai->ai_flags, 315 | ai->ai_family, 316 | PF_INET, 317 | PF_INET6, 318 | ai->ai_socktype, 319 | SOCK_STREAM, 320 | SOCK_DGRAM, 321 | ai->ai_protocol, 322 | IPPROTO_TCP, 323 | IPPROTO_UDP, 324 | ai->ai_addrlen, 325 | sizeof( struct sockaddr_in ), 326 | sizeof( struct sockaddr_in6 ) ); 327 | /* 328 | ** Now display the protocol-specific formatted socket address. Note 329 | ** that the program is requesting that getnameinfo(3) convert the 330 | ** host & service into numeric strings. 331 | */ 332 | getnameinfo( ai->ai_addr, 333 | ai->ai_addrlen, 334 | hostBfr, 335 | sizeof( hostBfr ), 336 | servBfr, 337 | sizeof( servBfr ), 338 | NI_NUMERICHOST | NI_NUMERICSERV ); 339 | switch ( ai->ai_family ) 340 | { 341 | case PF_INET: /* IPv4 address record. */ 342 | { 343 | struct sockaddr_in *p = (struct sockaddr_in*) ai->ai_addr; 344 | fprintf( stderr, 345 | " ai_addr = sin_family: %d (AF_INET = %d, " 346 | "AF_INET6 = %d)\n" 347 | " sin_addr: %s\n" 348 | " sin_port: %s\n", 349 | p->sin_family, 350 | AF_INET, 351 | AF_INET6, 352 | hostBfr, 353 | servBfr ); 354 | break; 355 | } /* End CASE of IPv4. */ 356 | case PF_INET6: /* IPv6 address record. */ 357 | { 358 | struct sockaddr_in6 *p = (struct sockaddr_in6*) ai->ai_addr; 359 | fprintf( stderr, 360 | " ai_addr = sin6_family: %d (AF_INET = %d, " 361 | "AF_INET6 = %d)\n" 362 | " sin6_addr: %s\n" 363 | " sin6_port: %s\n" 364 | " sin6_flowinfo: %d\n" 365 | " sin6_scope_id: %d\n", 366 | p->sin6_family, 367 | AF_INET, 368 | AF_INET6, 369 | hostBfr, 370 | servBfr, 371 | p->sin6_flowinfo, 372 | p->sin6_scope_id ); 373 | break; 374 | } /* End CASE of IPv6. */ 375 | default: /* Can never get here, but just for completeness. */ 376 | { 377 | fprintf( stderr, 378 | "%s (line %d): ERROR - Unknown protocol family (%d).\n", 379 | pgmName, 380 | __LINE__, 381 | ai->ai_family ); 382 | freeaddrinfo( aiHead ); 383 | return -1; 384 | } /* End DEFAULT case (unknown protocol family). */ 385 | } /* End SWITCH on protocol family. */ 386 | } /* End IF verbose mode. */ 387 | /* 388 | ** Create a socket using the info in the addrinfo structure. 389 | */ 390 | CHK( desc[ *descSize ] = socket( ai->ai_family, 391 | ai->ai_socktype, 392 | ai->ai_protocol ) ); 393 | /* 394 | ** Here is the code that prevents "IPv4 mapped addresses", as discussed 395 | ** in Section 22.1.3.1. If an IPv6 socket was just created, then set the 396 | ** IPV6_V6ONLY socket option. 397 | */ 398 | if ( ai->ai_family == PF_INET6 ) 399 | { 400 | #if defined( IPV6_V6ONLY ) 401 | /* 402 | ** Disable IPv4 mapped addresses. 403 | */ 404 | int v6Only = 1; 405 | CHK( setsockopt( desc[ *descSize ], 406 | IPPROTO_IPV6, 407 | IPV6_V6ONLY, 408 | &v6Only, 409 | sizeof( v6Only ) ) ); 410 | #else 411 | /* 412 | ** IPV6_V6ONLY is not defined, so the socket option can't be set and 413 | ** thus IPv4 mapped addresses can't be disabled. Print a warning 414 | ** message and close the socket. Design note: If the 415 | ** #if...#else...#endif construct were removed, then this program 416 | ** would not compile (because IPV6_V6ONLY isn't defined). That's an 417 | ** acceptable approach; IPv4 mapped addresses are certainly disabled 418 | ** if the program can't build! However, since this program is also 419 | ** designed to work for IPv4 sockets as well as IPv6, I decided to 420 | ** allow the program to compile when IPV6_V6ONLY is not defined, and 421 | ** turn it into a run-time warning rather than a compile-time error. 422 | ** IPv4 mapped addresses are still disabled because _all_ IPv6 traffic 423 | ** is disabled (all IPv6 sockets are closed here), but at least this 424 | ** way the server can still service IPv4 network traffic. 425 | */ 426 | fprintf( stderr, 427 | "%s (line %d): WARNING - Cannot set IPV6_V6ONLY socket " 428 | "option. Closing IPv6 %s socket.\n", 429 | pgmName, 430 | __LINE__, 431 | ai->ai_protocol == IPPROTO_TCP ? "TCP" : "UDP" ); 432 | CHK( close( desc[ *descSize ] ) ); 433 | continue; /* Go to top of FOR loop w/o updating *descSize! */ 434 | #endif /* IPV6_V6ONLY */ 435 | } /* End IF this is an IPv6 socket. */ 436 | /* 437 | ** Bind the socket. Again, the info from the addrinfo structure is used. 438 | */ 439 | CHK( bind( desc[ *descSize ], 440 | ai->ai_addr, 441 | ai->ai_addrlen ) ); 442 | /* 443 | ** If this is a TCP socket, put the socket into passive listening mode 444 | ** (listen is only valid on connection-oriented sockets). 445 | */ 446 | if ( ai->ai_socktype == SOCK_STREAM ) 447 | { 448 | CHK( listen( desc[ *descSize ], 449 | MAXCONNQLEN ) ); 450 | } 451 | /* 452 | ** Socket set up okay. Bump index to next descriptor array element. 453 | */ 454 | *descSize += 1; 455 | } /* End FOR each address info structure returned. */ 456 | /* 457 | ** Dummy check for unused address records. 458 | */ 459 | if ( verbose && ( ai != NULL ) ) 460 | { 461 | fprintf( stderr, 462 | "%s (line %d): WARNING - Some address records were " 463 | "not processed due to insufficient array space.\n", 464 | pgmName, 465 | __LINE__ ); 466 | } /* End IF verbose and some address records remain unprocessed. */ 467 | /* 468 | ** Clean up. 469 | */ 470 | freeaddrinfo( aiHead ); 471 | return 0; 472 | } /* End openSckt() */ 473 | /****************************************************************************** 474 | * Function: pit 475 | * 476 | * Description: 477 | * Listen on a set of sockets and send the current microsecond counter 478 | * that was produced by gettimeofday(), to any clients. This function 479 | * never returns. 480 | * 481 | * Parameters: 482 | * tSckt - Array of TCP socket descriptors on which to listen. 483 | * tScktSize - Size of the tSckt array (nbr of elements). 484 | * uSckt - Array of UDP socket descriptors on which to listen. 485 | * uScktSize - Size of the uSckt array (nbr of elements). 486 | * 487 | * Return Value: None. 488 | ******************************************************************************/ 489 | static void pit( int tSckt[ ], 490 | size_t tScktSize, 491 | int uSckt[ ], 492 | size_t uScktSize ) 493 | { 494 | char bfr[ 256 ]; 495 | ssize_t count; 496 | struct pollfd *desc; 497 | size_t descSize = tScktSize + uScktSize; 498 | int idx; 499 | int newSckt; 500 | struct sockaddr *sadr; 501 | socklen_t sadrLen; 502 | struct sockaddr_storage sockStor; 503 | int status; 504 | size_t timeLen; 505 | time_t timeVal; 506 | ssize_t wBytes; 507 | unsigned long long secs; 508 | int ret; 509 | /* 510 | ** Allocate memory for the poll(2) array. 511 | */ 512 | desc = malloc( descSize * sizeof( struct pollfd ) ); 513 | if ( desc == NULL ) 514 | { 515 | fprintf( stderr, 516 | "%s (line %d): ERROR - %s.\n", 517 | pgmName, 518 | __LINE__, 519 | strerror( ENOMEM ) ); 520 | exit( 1 ); 521 | } 522 | /* 523 | ** Initialize the poll(2) array. 524 | */ 525 | for ( idx = 0; idx < descSize; idx++ ) 526 | { 527 | desc[ idx ].fd = idx < tScktSize ? tSckt[ idx ] 528 | : uSckt[ idx - tScktSize ]; 529 | desc[ idx ].events = POLLIN; 530 | desc[ idx ].revents = 0; 531 | } 532 | /* 533 | ** Main PIT server loop. Handles both TCP & UDP requests. This is 534 | ** an interative server, and all requests are handled directly within the 535 | ** main loop. 536 | */ 537 | while ( true ) /* Do forever. */ 538 | { 539 | /* 540 | ** Wait for activity on one of the sockets. The DO..WHILE construct is 541 | ** used to restart the system call in the event the process is 542 | ** interrupted by a signal. 543 | */ 544 | do 545 | { 546 | status = poll( desc, 547 | descSize, 548 | -1 /* Wait indefinitely for input. */ ); 549 | } while ( ( status < 0 ) && ( errno == EINTR ) ); 550 | CHK( status ); /* Check for a bona fide system call error. */ 551 | /* 552 | ** Get the current time. 553 | */ 554 | #if defined(Windows) 555 | LARGE_INTEGER freq,counter; 556 | double wintime,bigcounter; 557 | /* For Windows the time_of_day() is useless. It increments in 55 milli 558 | * second increments. By using the Win32api one can get access to the 559 | * high performance measurement interfaces. With this one can get back 560 | * into the 8 to 9 microsecond resolution. 561 | */ 562 | QueryPerformanceFrequency(&freq); 563 | QueryPerformanceCounter(&counter); 564 | bigcounter=(double)counter.HighPart *(double)0xffffffff + 565 | (double)counter.LowPart; 566 | wintime = (double)(bigcounter/(double)freq.LowPart); 567 | secs = (long long)(wintime * 1000000); 568 | #else 569 | ret = gettimeofday( &tm,0 ); 570 | secs = ((unsigned long long)tm.tv_sec * 1000000) 571 | + (unsigned long long)tm.tv_usec; 572 | #endif 573 | 574 | ret = sprintf(timeStr,"%llu",secs); 575 | timeLen = strlen( timeStr ); 576 | /* 577 | ** Process sockets with input available. 578 | */ 579 | for ( idx = 0; idx < descSize; idx++ ) 580 | { 581 | switch ( desc[ idx ].revents ) 582 | { 583 | case 0: /* No activity on this socket; try the next. */ 584 | continue; 585 | case POLLIN: /* Network activity. Go process it. */ 586 | break; 587 | default: /* Invalid poll events. */ 588 | { 589 | fprintf( stderr, 590 | "%s (line %d): ERROR - Invalid poll event (0x%02X).\n", 591 | pgmName, 592 | __LINE__, 593 | desc[ idx ].revents ); 594 | exit( 1 ); 595 | } 596 | } /* End SWITCH on returned poll events. */ 597 | /* 598 | ** Determine if this is a TCP request or UDP request. 599 | */ 600 | if ( idx < tScktSize ) 601 | { 602 | /* 603 | ** TCP connection requested. Accept it. Notice the use of 604 | ** the sockaddr_storage data type. 605 | */ 606 | sadrLen = sizeof( sockStor ); 607 | sadr = (struct sockaddr*) &sockStor; 608 | CHK( newSckt = accept( desc[ idx ].fd, 609 | sadr, 610 | &sadrLen ) ); 611 | CHK( shutdown( newSckt, /* Server never recv's anything. */ 612 | SHUT_RD ) ); 613 | if ( verbose ) 614 | { 615 | /* 616 | ** Display the socket address of the remote client. Begin with 617 | ** the address-independent fields. 618 | */ 619 | fprintf( stderr, 620 | "Sockaddr info for new TCP client:\n" 621 | " sa_family = %d (AF_INET = %d, AF_INET6 = %d)\n" 622 | " addr len = %d (sockaddr_in = %zu, " 623 | "sockaddr_in6 = %zu)\n", 624 | sadr->sa_family, 625 | AF_INET, 626 | AF_INET6, 627 | sadrLen, 628 | sizeof( struct sockaddr_in ), 629 | sizeof( struct sockaddr_in6 ) ); 630 | /* 631 | ** Display the address-specific fields. 632 | */ 633 | getnameinfo( sadr, 634 | sadrLen, 635 | hostBfr, 636 | sizeof( hostBfr ), 637 | servBfr, 638 | sizeof( servBfr ), 639 | NI_NUMERICHOST | NI_NUMERICSERV ); 640 | /* 641 | ** Notice that we're switching on an address family now, not a 642 | ** protocol family. 643 | */ 644 | switch ( sadr->sa_family ) 645 | { 646 | case AF_INET: /* IPv4 address. */ 647 | { 648 | struct sockaddr_in *p = (struct sockaddr_in*) sadr; 649 | fprintf( stderr, 650 | " sin_addr = sin_family: %d\n" 651 | " sin_addr: %s\n" 652 | " sin_port: %s\n", 653 | p->sin_family, 654 | hostBfr, 655 | servBfr ); 656 | break; 657 | } /* End CASE of IPv4. */ 658 | case AF_INET6: /* IPv6 address. */ 659 | { 660 | struct sockaddr_in6 *p = (struct sockaddr_in6*) sadr; 661 | fprintf( stderr, 662 | " sin6_addr = sin6_family: %d\n" 663 | " sin6_addr: %s\n" 664 | " sin6_port: %s\n" 665 | " sin6_flowinfo: %d\n" 666 | " sin6_scope_id: %d\n", 667 | p->sin6_family, 668 | hostBfr, 669 | servBfr, 670 | p->sin6_flowinfo, 671 | p->sin6_scope_id ); 672 | break; 673 | } /* End CASE of IPv6. */ 674 | default: /* Can never get here, but for completeness. */ 675 | { 676 | fprintf( stderr, 677 | "%s (line %d): ERROR - Unknown address " 678 | "family (%d).\n", 679 | pgmName, 680 | __LINE__, 681 | sadr->sa_family ); 682 | break; 683 | } /* End DEFAULT case (unknown address family). */ 684 | } /* End SWITCH on address family. */ 685 | } /* End IF verbose mode. */ 686 | /* 687 | ** Send the PIT to the client. 688 | */ 689 | wBytes = timeLen; 690 | while ( wBytes > 0 ) 691 | { 692 | do 693 | { 694 | count = write( newSckt, 695 | timeStr, 696 | wBytes ); 697 | } while ( ( count < 0 ) && ( errno == EINTR ) ); 698 | CHK( count ); /* Check for an error. */ 699 | wBytes -= count; 700 | } /* End WHILE there is data to send. */ 701 | CHK( close( newSckt ) ); 702 | } /* End IF this was a TCP connection request. */ 703 | else 704 | { 705 | /* 706 | ** This is a UDP socket, and a datagram is available. The funny 707 | ** thing about UDP requests is that this server doesn't require any 708 | ** client input; but it can't send the PIT unless it knows a client 709 | ** wants the data, and the only way that can occur with UDP is if 710 | ** the server receives a datagram from the client. Thus, the 711 | ** server must receive _something_, but the content of the datagram 712 | ** is irrelevant. Read in the datagram. Again note the use of 713 | ** sockaddr_storage to receive the address. 714 | */ 715 | sadrLen = sizeof( sockStor ); 716 | sadr = (struct sockaddr*) &sockStor; 717 | CHK( count = recvfrom( desc[ idx ].fd, 718 | bfr, 719 | sizeof( bfr ), 720 | 0, 721 | sadr, 722 | &sadrLen ) ); 723 | /* 724 | ** Display whatever was received on stdout. 725 | */ 726 | if ( verbose ) 727 | { 728 | ssize_t rBytes = count; 729 | fprintf( stderr, 730 | "%s: UDP datagram received (%zd bytes).\n", 731 | pgmName, 732 | count ); 733 | while ( count > 0 ) 734 | { 735 | fputc( bfr[ rBytes - count-- ], 736 | stdout ); 737 | } 738 | if ( bfr[ rBytes-1 ] != '\n' ) 739 | fputc( '\n', stdout ); /* Newline also flushes stdout. */ 740 | /* 741 | ** Display the socket address of the remote client. Address- 742 | ** independent fields first. 743 | */ 744 | fprintf( stderr, 745 | "Remote client's sockaddr info:\n" 746 | " sa_family = %d (AF_INET = %d, AF_INET6 = %d)\n" 747 | " addr len = %d (sockaddr_in = %zu, " 748 | "sockaddr_in6 = %zu)\n", 749 | sadr->sa_family, 750 | AF_INET, 751 | AF_INET6, 752 | sadrLen, 753 | sizeof( struct sockaddr_in ), 754 | sizeof( struct sockaddr_in6 ) ); 755 | /* 756 | ** Display the address-specific information. 757 | */ 758 | getnameinfo( sadr, 759 | sadrLen, 760 | hostBfr, 761 | sizeof( hostBfr ), 762 | servBfr, 763 | sizeof( servBfr ), 764 | NI_NUMERICHOST | NI_NUMERICSERV ); 765 | switch ( sadr->sa_family ) 766 | { 767 | case AF_INET: /* IPv4 address. */ 768 | { 769 | struct sockaddr_in *p = (struct sockaddr_in*) sadr; 770 | fprintf( stderr, 771 | " sin_addr = sin_family: %d\n" 772 | " sin_addr: %s\n" 773 | " sin_port: %s\n", 774 | p->sin_family, 775 | hostBfr, 776 | servBfr ); 777 | break; 778 | } /* End CASE of IPv4 address. */ 779 | case AF_INET6: /* IPv6 address. */ 780 | { 781 | struct sockaddr_in6 *p = (struct sockaddr_in6*) sadr; 782 | fprintf( stderr, 783 | " sin6_addr = sin6_family: %d\n" 784 | " sin6_addr: %s\n" 785 | " sin6_port: %s\n" 786 | " sin6_flowinfo: %d\n" 787 | " sin6_scope_id: %d\n", 788 | p->sin6_family, 789 | hostBfr, 790 | servBfr, 791 | p->sin6_flowinfo, 792 | p->sin6_scope_id ); 793 | break; 794 | } /* End CASE of IPv6 address. */ 795 | default: /* Can never get here, but for completeness. */ 796 | { 797 | fprintf( stderr, 798 | "%s (line %d): ERROR - Unknown address " 799 | "family (%d).\n", 800 | pgmName, 801 | __LINE__, 802 | sadr->sa_family ); 803 | break; 804 | } /* End DEFAULT case (unknown address family). */ 805 | } /* End SWITCH on address family. */ 806 | } /* End IF verbose mode. */ 807 | /* 808 | ** Send the PIT to the client. 809 | */ 810 | wBytes = timeLen; 811 | while ( wBytes > 0 ) 812 | { 813 | do 814 | { 815 | count = sendto( desc[ idx ].fd, 816 | timeStr, 817 | wBytes, 818 | 0, 819 | sadr, /* Address & address length */ 820 | sadrLen ); /* received in recvfrom(). */ 821 | } while ( ( count < 0 ) && ( errno == EINTR ) ); 822 | CHK( count ); /* Check for a bona fide error. */ 823 | wBytes -= count; 824 | } /* End WHILE there is data to send. */ 825 | } /* End ELSE a UDP datagram is available. */ 826 | desc[ idx ].revents = 0; /* Clear the returned poll events. */ 827 | } /* End FOR each socket descriptor. */ 828 | } /* End WHILE forever. */ 829 | } /* End pit() */ 830 | 831 | -------------------------------------------------------------------------------- /tests/60-iozone/read_telemetry: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | # The format is: 4 | # 5 | # All fields are space delimited. 6 | # A # symbol in column 1 indicates a comment. 7 | # First field: Byte offset within the file. 8 | # Second field: Size in bytes of the I/O operation. 9 | # Third field: Number of milliseconds to delay before I/O operation. 10 | # 11 | # This is an example of sequential 64k reader with 2 milliseconds 12 | # before each read. 13 | # 14 | 0 65536 2 15 | 65536 65536 2 16 | 131072 65536 2 17 | 196608 65536 2 18 | 262144 65536 2 19 | 327680 65536 2 20 | 393216 65536 2 21 | 458752 65536 2 22 | 524288 65536 2 23 | 589824 65536 2 24 | 655360 65536 2 25 | 720896 65536 2 26 | 786432 65536 2 27 | 851968 65536 2 28 | 917504 65536 2 29 | 983040 65536 2 30 | -------------------------------------------------------------------------------- /tests/60-iozone/report.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # 3 | # arguments: one of more report files 4 | # 5 | # Christian Mautner , 2005-10-31 6 | # 7 | # This script is based loosely on the Generate_Graph set 8 | # of scripts that come with iozone, but is a complete re-write 9 | # 10 | # The main reason to write this was the need to compare the behaviour of 11 | # two or more different setups, for tuning filesystems or 12 | # comparing different pieces of hardware. 13 | # 14 | # This script is in the public domain, too short and too trivial 15 | # to deserve a copyright. 16 | # 17 | # Simply run iozone like, for example, ./iozone -a -g 4G > config1.out (if your machine has 4GB) 18 | # and then run perl report.pl config1.out 19 | # or get another report from another box into config2.out and run 20 | # perl report.pl config1.out config2.out 21 | # the look in the report_* directory for .png 22 | # 23 | # If you don't like png or the graphic size, search for "set terminal" in this file and put whatever gnuplot 24 | # terminal you want. Note I've also noticed that gnuplot switched the set terminal png syntax 25 | # a while back, you might need "set terminal png small size 900,700" 26 | # 27 | 28 | 29 | @Reports=@ARGV; 30 | 31 | die "usage: $0 [...]\n" if not @Reports or grep (m|^-|, @Reports); 32 | 33 | die "report files must be in current directory" if grep (m|/|, @Reports); 34 | 35 | %columns=( 36 | 'write' =>3, 37 | 'read' =>5, 38 | 'rewrite' =>4, 39 | 'reread' =>6, 40 | 'randread' =>7, 41 | 'randwrite' =>8, 42 | 'bkwdread' =>9, 43 | 'recrewrite'=>10, 44 | 'strideread'=>11, 45 | 'fwrite' =>12, 46 | 'frewrite' =>13, 47 | 'fread' =>14, 48 | 'freread' =>15, 49 | ); 50 | 51 | # 52 | # create output directory. the name is the concatenation 53 | # of all report file names (minus the file extension, plus 54 | # prefix report_) 55 | # 56 | $outdir="report_".join("_",map{/([^\.]+)(\..*)?/ && $1}(@Reports)); 57 | 58 | print STDERR "Output directory: $outdir "; 59 | 60 | if ( -d $outdir ) 61 | { 62 | print STDERR "(removing old directory) "; 63 | system "rm -rf $outdir"; 64 | } 65 | 66 | mkdir $outdir or die "cannot make directory $outdir"; 67 | 68 | print STDERR "done.\nPreparing data files..."; 69 | 70 | foreach $report (@Reports) 71 | { 72 | open(I, $report) or die "cannot open $report for reading"; 73 | $report=~/^([^\.]+)/; 74 | $datafile="$1.dat"; 75 | push @datafiles, $datafile; 76 | open(O, ">$outdir/$datafile") or die "cannot open $outdir/$datafile for writing"; 77 | open(O2, ">$outdir/2d-$datafile") or die "cannot open $outdir/$datafile for writing"; 78 | while() 79 | { 80 | next unless ( /^[\s\d]+$/ ); 81 | @split = split(); 82 | next unless ( @split >= 8 ); 83 | print O; 84 | print O2 if $split[1] == 16384 or $split[0] == $split[1]; 85 | } 86 | close I, O, O2; 87 | } 88 | 89 | print STDERR "done.\nGenerating graphs:"; 90 | 91 | foreach $column (keys %columns) 92 | { 93 | print STDERR " $column"; 94 | 95 | open(G, ">$outdir/$column.do") or die "cannot open $outdir/$column.do for writing"; 96 | print G qq{ 97 | set title "Iozone performance: $column" 98 | set grid lt 2 lw 1 99 | set surface 100 | set parametric 101 | set xtics 102 | set ytics 103 | set logscale x 2 104 | set logscale y 2 105 | set autoscale z 106 | #set xrange [2.**5:2.**24] 107 | set xlabel "File size in Kbytes" 108 | set ylabel "Record size in Kbytes" 109 | set zlabel "Kbytes/sec" 110 | set style data lines 111 | set dgrid3d 80,80,3 112 | #set terminal png small picsize 900 700 113 | set terminal png small size 900 700 114 | set output "$column.png" 115 | }; 116 | 117 | print G "splot ". join(", ", map{qq{"$_" using 1:2:$columns{$column} title "$_"}}(@datafiles)); 118 | 119 | print G "\n"; 120 | 121 | close G; 122 | 123 | open(G, ">$outdir/2d-$column.do") or die "cannot open $outdir/$column.do for writing"; 124 | print G qq{ 125 | set title "Iozone performance: $column" 126 | #set terminal png small picsize 450 350 127 | set terminal png small size 450 350 128 | set logscale x 129 | set xlabel "File size in Kbytes" 130 | set ylabel "Kbytes/sec" 131 | set output "2d-$column.png" 132 | }; 133 | 134 | print G "plot ". join(", ", map{qq{"2d-$_" using 1:$columns{$column} title "$_" with lines}}(@datafiles)); 135 | 136 | print G "\n"; 137 | 138 | close G; 139 | 140 | if ( system("cd $outdir && gnuplot $column.do && gnuplot 2d-$column.do") ) 141 | { 142 | print STDERR "(failed) "; 143 | } 144 | else 145 | { 146 | print STDERR "(ok) "; 147 | } 148 | } 149 | 150 | print STDERR "done.\n"; 151 | 152 | -------------------------------------------------------------------------------- /tests/60-iozone/spec.in: -------------------------------------------------------------------------------- 1 | Summary: Iozone Filesystem Benchmark 2 | Name: iozone 3 | Version: 3 4 | Release: 465 5 | License: Freeware 6 | Group: Applications/Engineering 7 | Source: %{name}%{version}_%{release}.tar 8 | Buildroot: /var/tmp/%{name}-buildroot 9 | 10 | %description 11 | IOzone is a filesystem benchmark tool. The benchmark generates and 12 | measures a variety of file operations. Iozone has been ported to many machines and runs under many operating systems. 13 | 14 | Iozone is useful for performing a broad filesystem analysis of a vendors 15 | computer platform. The benchmark tests file I/O performance for the following 16 | operations: Read, write, re-read, re-write, read backwards, read strided, 17 | fread, fwrite, random read, pread ,mmap, aio_read, aio_write. 18 | 19 | 20 | ## 21 | ## PREP 22 | ## 23 | %prep 24 | 25 | ## 26 | ## SETUP and PATCH 27 | ## 28 | %setup -n iozone3_465/src/current 29 | 30 | 31 | ## 32 | ## BUILD 33 | ## 34 | ## 35 | ## BUILD 36 | ## 37 | %build 38 | %ifarch %{ix86} 39 | make linux 40 | %else 41 | %ifarch x86_64 42 | make linux-AMD64 43 | %else 44 | %ifarch ia64 45 | make linux-ia64 46 | %else 47 | %ifarch ppc 48 | make linux-powerpc 49 | %else 50 | %ifarch ppc64 51 | make linux-powerpc64 52 | %else 53 | %ifarch s390 54 | make linux-S390 55 | %else 56 | %ifarch s390x 57 | make linux-S390X 58 | %else 59 | %ifarch %(arm) 60 | make linux-arm 61 | %else 62 | echo "No idea how to build for your arch..." 63 | exit 1 64 | %endif 65 | %endif 66 | %endif 67 | %endif 68 | %endif 69 | %endif 70 | %endif 71 | %endif 72 | 73 | ## 74 | ## INSTALL 75 | ## 76 | %install 77 | mkdir -p $RPM_BUILD_ROOT/opt/iozone/bin 78 | cp $RPM_BUILD_DIR/iozone3_465/src/current/iozone $RPM_BUILD_ROOT/opt/iozone/bin/ 79 | cp $RPM_BUILD_DIR/iozone3_465/src/current/fileop $RPM_BUILD_ROOT/opt/iozone/bin/ 80 | cp $RPM_BUILD_DIR/iozone3_465/src/current/pit_server $RPM_BUILD_ROOT/opt/iozone/bin/ 81 | cp $RPM_BUILD_DIR/iozone3_465/src/current/Generate_Graphs $RPM_BUILD_ROOT/opt/iozone/bin/ 82 | cp $RPM_BUILD_DIR/iozone3_465/src/current/gengnuplot.sh $RPM_BUILD_ROOT/opt/iozone/bin/ 83 | cp $RPM_BUILD_DIR/iozone3_465/src/current/gnu3d.dem $RPM_BUILD_ROOT/opt/iozone/bin/ 84 | 85 | mkdir -p $RPM_BUILD_ROOT/opt/iozone/docs 86 | cp $RPM_BUILD_DIR/iozone3_465/docs/IOzone_msword_98.pdf $RPM_BUILD_ROOT/opt/iozone/docs/ 87 | cp $RPM_BUILD_DIR/iozone3_465/docs/Run_rules.doc $RPM_BUILD_ROOT/opt/iozone/docs/ 88 | cp $RPM_BUILD_DIR/iozone3_465/docs/IOzone_msword_98.doc $RPM_BUILD_ROOT/opt/iozone/docs/ 89 | cp $RPM_BUILD_DIR/iozone3_465/docs/Iozone_ps.gz $RPM_BUILD_ROOT/opt/iozone/docs/ 90 | cp $RPM_BUILD_DIR/iozone3_465/src/current/Gnuplot.txt $RPM_BUILD_ROOT/opt/iozone/docs/ 91 | 92 | mkdir -p $RPM_BUILD_ROOT/opt/iozone/man/man1 93 | cp $RPM_BUILD_DIR/iozone3_465/docs/iozone.1 $RPM_BUILD_ROOT/opt/iozone/man/man1/ 94 | 95 | 96 | ## 97 | ## FILES 98 | ## 99 | %files 100 | %attr(755,root,root) /opt/ 101 | 102 | 103 | ## 104 | ## CLEAN 105 | ## 106 | %clean 107 | rm -rf $RPM_BUILD_ROOT 108 | -------------------------------------------------------------------------------- /tests/60-iozone/write_telemetry: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | # The format is: 4 | # 5 | # All fields are space delimited. 6 | # A # symbol in column 1 indicates a comment. 7 | # First field: Byte offset within the file. 8 | # Second field: Size in bytes of the I/O operation. 9 | # Third field: Number of milliseconds to delay before I/O operation. 10 | # 11 | # This is an example of sequential 64k writer with 2 milliseconds 12 | # before each write. 13 | # 14 | 0 65536 2 15 | 65536 65536 2 16 | 131072 65536 2 17 | 196608 65536 2 18 | 262144 65536 2 19 | 327680 65536 2 20 | 393216 65536 2 21 | 458752 65536 2 22 | 524288 65536 2 23 | 589824 65536 2 24 | 655360 65536 2 25 | 720896 65536 2 26 | 786432 65536 2 27 | 851968 65536 2 28 | 917504 65536 2 29 | 983040 65536 2 30 | -------------------------------------------------------------------------------- /tests/70-nginx.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtth-bfft/muslkl/d6dcfdef0eda1e6ce2bbd02303af6a58e5c5ce44/tests/70-nginx.img -------------------------------------------------------------------------------- /tests/80-memcached.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtth-bfft/muslkl/d6dcfdef0eda1e6ce2bbd02303af6a58e5c5ce44/tests/80-memcached.img -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mak 2 | 3 | .PHONY: default all tests memcached nginx clean 4 | 5 | default: tests 6 | all: tests iozone memcached nginx 7 | 8 | ${TESTS_BUILD}/%: %.c ${SGX_MUSL_CC} | ${TESTS_BUILD} 9 | ${SGX_MUSL_CC} ${MY_CFLAGS} -o $@ $< ${MY_LDFLAGS} 10 | 11 | # Run tests (in a sub-target to prevent Make from parallelising different tests) 12 | tests: $(TESTS_OBJ) 13 | @${MAKE} -j1 serial_tests 14 | 15 | tests_norun: $(TESTS_OBJ) 16 | 17 | serial_tests: 18 | @printf " [*] 01-compiler: " 19 | @MUSL_NOLKL=1 ${TESTS_BUILD}/01-compiler >/dev/null; \ 20 | [ $$? -eq 42 ] && echo "OK" 21 | @printf " [*] 02-sleep: " 22 | @MUSL_NOLKL=1 ${MUSLKLSGX_STD_RUN_OPTS} ${TESTS_BUILD}/02-sleep >/dev/null; \ 23 | [ $$? -eq 0 ] && echo "OK" 24 | @printf " [*] 03-pthreads: " 25 | @MUSL_NOLKL=1 ${MUSLKLSGX_STD_RUN_OPTS} ${TESTS_BUILD}/03-pthreads >/dev/null; \ 26 | [ $$? -eq 0 ] && echo "OK" 27 | # @printf " [*] 04-lthreads-sleep: " 28 | # @MUSL_NOLKL=1 ${MUSLKLSGX_STD_RUN_OPTS} ${TESTS_BUILD}/04-lthreads-sleep; \ 29 | # [ $$? -eq 0 ] && echo "OK" 30 | @printf " [*] 05-devrandom: " 31 | @MUSL_NOLKL=0 ${MUSLKLSGX_STD_RUN_OPTS} ${TESTS_BUILD}/05-devrandom >/dev/null; \ 32 | [ $$? -eq 0 ] && echo "OK" 33 | @printf " [*] 10-lkl-host-print: " 34 | @MUSL_NOLKL=1 ${TESTS_BUILD}/10-lkl-host-print 2>&1 | grep -qi ok; \ 35 | [ $$? -eq 0 ] && echo "OK" 36 | @printf " [*] 11-lkl-host-panic: " 37 | @MUSL_NOLKL=1 ${TESTS_BUILD}/11-lkl-host-panic >/dev/null 2>&1; \ 38 | [ $$? -ne 0 ] && echo "OK" 39 | @rm -f /tmp/encl-lb-* 40 | @printf " [*] 12-lkl-host-mem: " 41 | @MUSL_NOLKL=1 ${TESTS_BUILD}/12-lkl-host-mem >/dev/null; \ 42 | [ $$? -eq 0 ] && echo "OK" 43 | @printf " [*] 13-lkl-host-thread: " 44 | @MUSL_NOLKL=1 ${TESTS_BUILD}/13-lkl-host-thread >/dev/null; \ 45 | [ $$? -eq 0 ] && echo "OK" 46 | @printf " [*] 14-lkl-host-tls: " 47 | @MUSL_NOLKL=1 ${TESTS_BUILD}/14-lkl-host-tls >/dev/null; \ 48 | [ $$? -eq 0 ] && echo "OK" 49 | @printf " [*] 15-lkl-host-mutex: " 50 | @MUSL_NOLKL=1 ${TESTS_BUILD}/15-lkl-host-mutex >/dev/null; \ 51 | [ $$? -eq 0 ] && echo "OK" 52 | @printf " [*] 16-lkl-host-semaphore: " 53 | @MUSL_NOLKL=1 ${TESTS_BUILD}/16-lkl-host-semaphore >/dev/null; \ 54 | [ $$? -eq 0 ] && echo "OK" 55 | @printf " [*] 17-lkl-host-time: " 56 | @MUSL_NOLKL=1 ${TESTS_BUILD}/17-lkl-host-time >/dev/null; \ 57 | [ $$? -eq 0 ] && echo "OK" 58 | @printf " [*] 18-lkl-host-timer: " 59 | @MUSL_NOLKL=1 ${MUSLKLSGX_STD_RUN_OPTS} ${TESTS_BUILD}/18-lkl-host-timer >/dev/null; \ 60 | [ $$? -eq 0 ] && echo "OK" 61 | @printf " [*] 19-lkl-boot: " 62 | @MUSL_NOLKL=0 ${MUSLKLSGX_STD_RUN_OPTS} MUSL_TAP="" MUSL_HD="" ${TESTS_BUILD}/19-lkl-boot >/dev/null; \ 63 | [ $$? -eq 42 ] && echo "OK" 64 | @printf " [*] 20-lkl-disk: (plaintext) " 65 | @cd ${TESTS}; tar -xvf 20-lkl-disk.tar.gz >/dev/null 66 | @MUSL_NOLKL=0 ${MUSLKLSGX_STD_RUN_OPTS} MUSL_TAP="" MUSL_HD=${TESTS}/20-lkl-disk.img ${TESTS_BUILD}/20-lkl-disk >/dev/null; \ 67 | [ $$? -eq 0 ] && echo "OK" 68 | @printf " [*] 20-lkl-disk: (encrypted) " 69 | @${TOOLS_BUILD}/disk_encrypt -e -k 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F \ 70 | -i ${TESTS}/20-lkl-disk.img -o ${TESTS}/20-lkl-disk-encrypted.img >/dev/null 2>&1 71 | @MUSL_NOLKL=0 ${MUSLKLSGX_STD_RUN_OPTS} MUSL_TAP="" MUSL_HD=${TESTS}/20-lkl-disk-encrypted.img ${TESTS_BUILD}/20-lkl-disk >/dev/null; \ 72 | [ $$? -eq 0 ] && echo "OK" 73 | @rm -f ${TESTS}/20-lkl-disk.img ${TESTS}/20-lkl-disk-encrypted.img 74 | @printf " [*] 21-lkl-net: " 75 | @(MUSL_NOLKL=0 ${MUSLKLSGX_STD_RUN_OPTS} MUSL_TAP=tap0 MUSL_IP4=10.0.1.1 MUSL_GW4=10.0.1.254 MUSL_MASK4=24 MUSL_HD="" \ 76 | ${TESTS_BUILD}/21-lkl-net >/dev/null &) && (ping -W1 -c15 -i0.2 -D -O -q -n 10.0.1.1 >/dev/null); \ 77 | [ $$? -eq 0 ] && echo "OK" 78 | 79 | iozone: 80 | +${MAKE} -C ${IOZONE} CC=${SGX_MUSL_CC} CFLAGS="-DHAVE_PREADV -DHAVE_PWRITEV" openbsd-threads 81 | # Using openbsd-threads instead of linux is just a trick to disable aio async read/writes, not supported in sgx-musl. 82 | 83 | libevent: ${LIBEVENT_BUILD} | ${LIBEVENT}/.git 84 | cd ${LIBEVENT}; [ -f configure ] || CC=${SGX_MUSL_CC} ./autogen.sh 85 | cd ${LIBEVENT}; MUSL_NOLKL=0 ${MUSLKLSGX_STD_RUN_OPTS} MUSL_HD="" MUSL_TAP="" CC=${SGX_MUSL_CC} ./configure \ 86 | --disable-shared \ 87 | --disable-openssl \ 88 | --prefix=${LIBEVENT_BUILD} 89 | #FIXME: autoconf fails to detect type sizes. Hard-code them for x86_64 with a sed. 90 | sed -i -e 's/EVENT__SIZEOF_INT $$/EVENT__SIZEOF_INT 4/' \ 91 | -e 's/EVENT__SIZEOF_LONG $$/EVENT__SIZEOF_LONG 8/' \ 92 | -e 's/EVENT__SIZEOF_LONG_LONG $$/EVENT__SIZEOF_LONG_LONG 8/' \ 93 | -e 's/EVENT__SIZEOF_OFF_T $$/EVENT__SIZEOF_OFF_T 8/' \ 94 | -e 's/EVENT__SIZEOF_PTHREAD_T $$/EVENT__SIZEOF_PTHREAD_T 8/' \ 95 | -e 's/EVENT__SIZEOF_SHORT $$/EVENT__SIZEOF_SHORT 2/' \ 96 | -e 's/EVENT__SIZEOF_SIZE_T $$/EVENT__SIZEOF_SIZE_T 8/' \ 97 | -e 's/EVENT__SIZEOF_VOID_P $$/EVENT__SIZEOF_VOID_P 8/' ${LIBEVENT}/include/event2/event-config.h 98 | +${MAKE} -C ${LIBEVENT} 99 | +${MAKE} -C ${LIBEVENT} install 100 | 101 | memcached: libevent ${MEMCACHED_BUILD} | ${MEMCACHED}/.git 102 | cd ${MEMCACHED}; [ -f configure ] || ./autogen.sh 103 | cd ${MEMCACHED}; MUSL_NOLKL=0 ${MUSLKLSGX_STD_RUN_OPTS} MUSL_HD="" MUSL_TAP="" CC=${SGX_MUSL_CC} ./configure \ 104 | --with-libevent=${LIBEVENT_BUILD} \ 105 | --mandir=/tmp \ 106 | --disable-coverage \ 107 | --prefix=${MEMCACHED_BUILD} 108 | +${MAKE} -C ${MEMCACHED} 109 | +${MAKE} -C ${MEMCACHED} install 110 | 111 | nginx: ${NGINX_BUILD} | ${NGINX}/.git 112 | cd ${NGINX}; ${MUSLKLSGX_STD_RUN_OPTS} MUSL_HD="" MUSL_TAP="" CC=${SGX_MUSL_CC} ./auto/configure \ 113 | ${NGINX_CONFIGURE_OPTS} \ 114 | --prefix=${NGINX_BUILD}/ \ 115 | --conf-path=/data/conf/nginx.conf \ 116 | --sbin-path=/none \ 117 | --pid-path=/tmp/nginx.pid \ 118 | --lock-path=/tmp/nginx.lock \ 119 | --error-log-path=/tmp/error.log \ 120 | --http-log-path=/tmp/access.log \ 121 | --http-client-body-temp-path=/tmp/client-body \ 122 | --http-proxy-temp-path=/tmp/proxy \ 123 | --http-fastcgi-temp-path=/tmp/fastcgi \ 124 | --http-fastcgi-temp-path=/tmp/fastcgi \ 125 | --http-uwsgi-temp-path=/tmp/uwsgi \ 126 | --http-scgi-temp-path=/tmp/scgi \ 127 | --without-http_gzip_module \ 128 | --without-http_rewrite_module \ 129 | --with-ipv6 \ 130 | --with-http_ssl_module \ 131 | --with-openssl=${OPENSSL} \ 132 | --with-cc="${SGX_MUSL_CC}" 133 | cd ${NGINX}; ${MUSLKLSGX_STD_RUN_OPTS} MUSL_HD="" MUSL_TAP="" CC=${SGX_MUSL_CC} make 134 | 135 | # Build directories initialisation (one-shot after git clone and make clean) 136 | ${LIBEVENT_BUILD} ${MEMCACHED_BUILD} ${NGINX_BUILD} ${TESTS_BUILD}: 137 | @mkdir -p $@ 138 | 139 | # Submodule initialisation (one-shot after git clone) 140 | ${LIBEVENT}/.git ${MEMCACHED}/.git ${NGINX}/.git: 141 | [ "$(FORCE_SUBMODULES_VERSION)" = "true" ] || git submodule update --init $($@:.git=) 142 | clean: 143 | rm -f $(TESTS_OBJ) 144 | ${MAKE} -C ${IOZONE} clean 145 | ${MAKE} -C ${LIBEVENT} clean || /bin/true 146 | rm -f ${LIBEVENT}/Makefile 147 | rm -f ${LIBEVENT}/configure 148 | ${MAKE} -C ${MEMCACHED} clean || /bin/true 149 | rm -f ${MEMCACHED}/Makefile 150 | rm -f ${MEMCACHED}/configure 151 | -------------------------------------------------------------------------------- /tools/bench/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mtth-bfft/muslkl/d6dcfdef0eda1e6ce2bbd02303af6a58e5c5ce44/tools/bench/__init__.py -------------------------------------------------------------------------------- /tools/bench/benchmark.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import re 5 | import sys 6 | import subprocess 7 | import signal 8 | import time 9 | import datetime 10 | import threading 11 | 12 | ROOT_PATH = os.path.realpath( 13 | os.path.dirname(os.path.abspath( __file__ )) + '/../../' 14 | ) 15 | DEFAULT_VANILLA_CMDLINE = ROOT_PATH + \ 16 | '/../vanilla-sgx-musl/memcached-1.4.30/memcached -t{appthreads} -M -u root' 17 | DEFAULT_CUSTOM_CMDLINE = ROOT_PATH + \ 18 | '/build/tests/80-memcached/memcached/bin/memcached -t{appthreads} -M -u root' 19 | DEFAULT_BENCH_CWD = ROOT_PATH + '/../YCSB/' 20 | DEFAULT_BENCH_CMDLINES = [ 21 | ROOT_PATH + '/../YCSB/bin/ycsb load memcached -threads 10 -s ' + \ 22 | '-P workloads/workload{ycsb} -p memcached.hosts={ip}', 23 | ROOT_PATH + '/../YCSB/bin/ycsb run memcached -threads {clients} ' + \ 24 | '-s -P workloads/workload{ycsb} -p memcached.hosts={ip}', 25 | ] 26 | DEFAULT_BENCH_IP4 = '10.0.1.1' 27 | DEFAULT_BENCH_GW4 = '10.0.1.254' 28 | DEFAULT_BENCH_MASK4 = 24 29 | DEFAULT_BENCH_TAP = 'tap0' 30 | DEFAULT_BENCH_HD = ROOT_PATH + '/tests/80-memcached.img' 31 | DEFAULT_BENCH_TIMEOUT = 20 # seconds 32 | DEFAULT_SERVER_WAITSTOP = 1 # seconds 33 | 34 | class Benchmark(): 35 | TYPE_VANILLA = "Host kernel" 36 | TYPE_LKL = "LKL kernel" 37 | 38 | def __init__(self, type, ethreads=2, sthreads=100, clients=1, 39 | espins=500, esleep=16000, sspins=100, ssleep=4000, 40 | appthreads=2, ycsb='a', slots=256, 41 | kernel=True): 42 | self.type = type 43 | self.ycsb = ycsb 44 | self.kernel = kernel 45 | self.ethreads = ethreads 46 | self.sthreads = sthreads 47 | self.espins = espins 48 | self.esleep = esleep 49 | self.sspins = sspins 50 | self.ssleep = ssleep 51 | self.appthreads = appthreads 52 | self.clients = clients 53 | self.srv_pid = None 54 | self.srv_out = '' 55 | if type == Benchmark.TYPE_VANILLA: 56 | self.bench_ip4 = '127.0.0.1' 57 | else: 58 | self.bench_ip4 = DEFAULT_BENCH_IP4 59 | self.bench_timeout = DEFAULT_BENCH_TIMEOUT 60 | self.bench_cmdlines = [ 61 | cmd.format( 62 | ip = self.bench_ip4, 63 | ycsb = self.ycsb, 64 | clients = self.clients, 65 | ) for cmd in DEFAULT_BENCH_CMDLINES 66 | ] 67 | 68 | if type == Benchmark.TYPE_VANILLA: 69 | self.srv_cmdline = DEFAULT_VANILLA_CMDLINE 70 | elif type == Benchmark.TYPE_LKL: 71 | self.srv_cmdline = DEFAULT_CUSTOM_CMDLINE 72 | else: 73 | raise ValueError("Unknown benchmark type") 74 | self.srv_cmdline = self.srv_cmdline.format( 75 | appthreads=self.appthreads, 76 | ) 77 | 78 | def server_thread(self): 79 | srv_env = os.environ.copy() 80 | srv_env["MUSL_RTPRIO"] = 1 81 | srv_env["MUSL_KERNEL"] = 1 if self.kernel else 0 82 | srv_env["MUSL_ETHREADS"] = self.ethreads 83 | srv_env["MUSL_STHREADS"] = self.sthreads 84 | srv_env["MUSL_ESPINS"] = self.espins 85 | srv_env["MUSL_ESLEEP"] = self.esleep 86 | srv_env["MUSL_SSPINS"] = self.sspins 87 | srv_env["MUSL_SSLEEP"] = self.ssleep 88 | srv_env["MUSL_NOLKL"] = 0 89 | srv_env["MUSL_VERBOSELKL"] = 0 90 | srv_env["MUSL_HD"] = DEFAULT_BENCH_HD 91 | srv_env["MUSL_TAP"] = DEFAULT_BENCH_TAP 92 | srv_env["MUSL_IP4"] = DEFAULT_BENCH_IP4 93 | srv_env["MUSL_GW4"] = DEFAULT_BENCH_GW4 94 | srv_env["MUSL_MASK4"] = DEFAULT_BENCH_MASK4 95 | srv_env = { k : str(v) for (k,v) in srv_env.items() } 96 | self.srv_out = '' 97 | srv_proc = None 98 | err = None 99 | print(' [*] Starting server ' + self.srv_cmdline) 100 | try: 101 | srv_proc = subprocess.Popen(self.srv_cmdline.split(), 102 | stdout=subprocess.PIPE, stderr=subprocess.STDOUT, 103 | universal_newlines=True, start_new_session=True, 104 | env=srv_env) 105 | self.srv_pid = srv_proc.pid 106 | self.srv_out = srv_proc.communicate()[0] 107 | except Exception as e: 108 | err = e 109 | if err is not None: 110 | raise RuntimeError( 111 | ("Benchmarked server died: %s %s\n" +\ 112 | "====\n%s") % (str(type(e)), str(e), self.srv_out)) 113 | if not self.killed: 114 | raise RuntimeError( 115 | ("Benchmark server exited with code %d before " + \ 116 | "the end:\n====\n%s") % (int(srv_proc.poll()), 117 | self.srv_out)) 118 | print(' [*] Server killed normally') 119 | 120 | def start_server(self): 121 | self.killed = False 122 | srv_thread = threading.Thread(target=self.server_thread) 123 | srv_thread.start() 124 | 125 | def stop_server(self): 126 | if not self.killed and self.srv_pid is not None: 127 | print(' [*] Killing server') 128 | self.killed = True 129 | os.killpg(self.srv_pid, signal.SIGINT) 130 | self.srv_pid = None 131 | else: 132 | print(' [*] Server already killed') 133 | time.sleep(DEFAULT_SERVER_WAITSTOP) 134 | 135 | def parse_output(self, out): 136 | def extract(var, txt): 137 | return float(re.search(r'^.*' + var + '.*\s(\d+(\.\d+)?)\D*$', 138 | txt, re.IGNORECASE|re.MULTILINE).group(1)) 139 | loadpos = out.find('[OVERALL], RunTime') 140 | runpos = out.find('[OVERALL], RunTime', loadpos+1) 141 | if loadpos < 0 or runpos < 0: 142 | raise ValueError("Unable to parse benchmark output:\n%s" % out) 143 | load = out[loadpos:runpos] 144 | run = out[runpos:] 145 | self.load_throughput = extract('overall.*throughput', load) 146 | self.insert_latency_avg = extract('insert.*average.*latency', load) 147 | self.insert_latency_min = extract('insert.*min.*latency', load) 148 | self.insert_latency_max = extract('insert.*max.*latency', load) 149 | self.insert_latency_95 = extract('insert.*95.*latency', load) 150 | self.run_throughput = extract('overall.*throughput', run) 151 | self.read_latency_avg = extract('read.*average.*latency', run) 152 | self.read_latency_min = extract('read.*min.*latency', run) 153 | self.read_latency_max = extract('read.*max.*latency', run) 154 | self.read_latency_95 = extract('read.*95.*latency', run) 155 | self.update_latency_avg = extract('update.*average.*latency', run) 156 | self.update_latency_min = extract('update.*min.*latency', run) 157 | self.update_latency_max = extract('update.*max.*latency', run) 158 | self.update_latency_95 = extract('update.*95.*latency', run) 159 | self.throughput = self.run_throughput 160 | self.latency = (self.read_latency_avg + self.update_latency_avg)/2 161 | 162 | def run(self): 163 | self.start_time = time.time() 164 | output, cmdline = '', '' 165 | # This part of the code cannot use Popen(timeout) because 166 | # it waits indefinitely for subprocesses to die. 167 | proc = None 168 | try: 169 | self.start_server() 170 | for cmdline in self.bench_cmdlines: 171 | print(' [*] Running benchmark cmd: ' + cmdline) 172 | proc = subprocess.Popen(cmdline.split(), 173 | stdout=subprocess.PIPE, 174 | stderr=subprocess.STDOUT, universal_newlines=True, 175 | start_new_session=True, cwd=DEFAULT_BENCH_CWD) 176 | output += proc.communicate(timeout=self.bench_timeout)[0] 177 | except subprocess.TimeoutExpired: 178 | os.killpg(proc.pid, signal.SIGKILL) 179 | output += proc.communicate()[0] 180 | raise RuntimeError( 181 | "Benchmark cmd timed out:\n%s\n%s" % (cmdline, output) 182 | ) 183 | except Exception as e: 184 | if proc is not None and proc.poll() is None: 185 | os.killpg(proc.pid, signal.SIGKILL) 186 | if proc is None or proc.poll() is None: 187 | ret = -1 188 | else: 189 | ret = proc.poll() 190 | output += proc.communicate()[0] 191 | raise RuntimeError( 192 | ("Benchmark cmd exited with code %d:\n" + \ 193 | "=========\n%s") % (int(ret), output)) 194 | finally: 195 | self.stop_server() 196 | if proc is not None and proc.poll() is None: 197 | os.killpg(proc.pid, signal.SIGKILL) 198 | try: 199 | self.parse_output(output) 200 | except Exception as e: 201 | raise RuntimeError( 202 | ("Benchmark gave unexpected output: %s %s\n" + \ 203 | "=========\n" + \ 204 | "%s\n" + \ 205 | "=========\n" + \ 206 | "%s") % (str(type(e)), str(e), cmdline, output) 207 | ) 208 | self.stop_time = time.time() 209 | self.elapsed_time = self.stop_time - self.start_time 210 | 211 | -------------------------------------------------------------------------------- /tools/bench/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from datetime import timedelta 4 | 5 | def pretty_print_duration(secs): 6 | if type(secs) is timedelta: 7 | return str(secs) 8 | else: 9 | return str(timedelta(seconds=int(secs))) 10 | 11 | def pretty_print_size(bytes): 12 | prefixes = ['B','KiB','MiB','GiB'] 13 | prefix = 0 14 | while bytes > 1024 and prefix < len(prefixes): 15 | bytes /= 1024 16 | prefix += 1 17 | return str(bytes) + prefixes[prefix] 18 | 19 | def range_custom(a, b, step="+1"): 20 | val = a 21 | mult = 1 22 | add = 0 23 | if len(step)>=2 and step[0] == 'x': 24 | mult = int(step[1:]) 25 | else: 26 | add = int(step) 27 | while val <= b: 28 | val += add 29 | val *= mult 30 | yield val 31 | 32 | def parse_timedelta(txt): 33 | try: 34 | txt = txt.lower() 35 | val = int(txt[:-1]) 36 | if txt.endswith('s'): 37 | return val 38 | elif txt.endswith('m'): 39 | return val*60 40 | elif txt.endswith('h'): 41 | return val*3600 42 | elif txt.endswith('d'): 43 | return val*3600*24 44 | except: 45 | pass 46 | return None 47 | 48 | -------------------------------------------------------------------------------- /tools/bench_encryption.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | import re 6 | import time 7 | import base64 8 | import subprocess 9 | import signal 10 | import statistics 11 | from collections import OrderedDict 12 | 13 | test_duration = 20 14 | test_repeats = 5 15 | 16 | tools_dir = os.path.dirname(os.path.realpath(__file__)) 17 | tool_path = tools_dir + '/../build/tools/disk_encrypt' 18 | random_bits = os.urandom(128) 19 | random_pass = base64.b64encode(random_bits) 20 | 21 | commands = OrderedDict() 22 | commands['/dev/random'] = tool_path + ' -i /dev/random' 23 | commands['/dev/urandom'] = tool_path + ' -i /dev/urandom' 24 | commands['OpenSSL AES256-CTR'] = ('openssl enc -aes-256-ctr -pass pass:"%s" -nosalt '+\ 25 | '< /dev/zero | %s') % (random_pass, tool_path) 26 | commands['/dev/zero'] = tool_path + ' -i /dev/zero' 27 | 28 | def get_bench_results(cmd): 29 | results = [] 30 | for iteration in range(test_repeats): 31 | proc = subprocess.Popen(cmd, shell=True, universal_newlines=True, 32 | stdout=subprocess.PIPE, stderr=subprocess.STDOUT, 33 | preexec_fn=os.setsid) 34 | time.sleep(test_duration) 35 | os.killpg(os.getpgid(proc.pid), signal.SIGINT) 36 | out, _ = proc.communicate() 37 | bytes = re.search(r'\b(\d+)\b\W*bytes', out) 38 | secs = re.search(r'\b(\d+)\b\W*seconds', out) 39 | if bytes is None or secs is None: 40 | raise RuntimeError("Unable to parse benchmark output: %s" % out) 41 | results.append(float(bytes.group(1))/int(secs.group(1))) 42 | return (statistics.mean(results), statistics.stdev(results)) 43 | 44 | if __name__ == '__main__': 45 | sys.stdout.write(' '*20 + ' Encryption | Decryption\n') 46 | for name, cmd in commands.items(): 47 | cmd += ' -o /dev/null' 48 | cmd += ' -k0102030405060708091011121314151617181920212223242526272829303132' 49 | sys.stdout.write(name.rjust(20) + ' ') 50 | sys.stdout.flush() 51 | mean, stdev = get_bench_results(cmd + ' -e') 52 | sys.stdout.write('{:9.4f} MiB/s ({:.2f} %) '.format( 53 | float(mean)/(1024*1024), float(stdev)/mean*100)) 54 | sys.stdout.flush() 55 | mean, stdev = get_bench_results(cmd + ' -e') 56 | sys.stdout.write('{:9.4f} MiB/s ({:.2f} %)'.format( 57 | float(mean)/(1024*1024), float(stdev)/mean*100)) 58 | print('') 59 | 60 | -------------------------------------------------------------------------------- /tools/bench_iozone_recordsize.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import re 5 | import sys 6 | import subprocess 7 | import statistics 8 | import csv 9 | from bench.utils import pretty_print_size, pretty_print_duration 10 | from datetime import datetime 11 | import matplotlib.pyplot as plt 12 | 13 | # Installation paths and test encryption keys 14 | syscalldrv_path = '/dev/syscall0' 15 | root_path = os.path.dirname(os.path.realpath(__file__)) 16 | iozone_path = root_path + '/../tests/60-iozone/iozone' 17 | encrypt_tool_path = root_path + '/../build/tools/disk_encrypt' 18 | encrypt_default_key = '000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F' 19 | 20 | # System-dependent functions 21 | def flush_caches(): 22 | if os.geteuid() != 0: 23 | return 24 | os.system('echo 3 >/proc/sys/vm/drop_caches') 25 | 26 | # Detect binaries compiled with heavy debug options 27 | def is_debug_executable(path): 28 | res = subprocess.check_output(['strings', path], shell=False, 29 | universal_newlines=True, stderr=subprocess.PIPE) 30 | match = re.search(r'^musl.*debug', res, flags=re.MULTILINE|re.IGNORECASE) 31 | return (match is not None) 32 | 33 | def total_ram_bytes(): 34 | return os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES') 35 | 36 | class IOZoneBenchmark(object): 37 | 38 | def __init__(self, root=True, kernel=True, recordsizes=range(1,33), 39 | repeats=5, max_rsd=0.10, ethreads=4, sthreads=100, 40 | espins=200, esleep=14000, sspins=100, ssleep=8000): 41 | 42 | self.recordsizes = list(recordsizes) 43 | self.repeats = repeats 44 | self.max_rsd = max_rsd 45 | self.kernel = kernel 46 | self.root = root 47 | self.ethreads = ethreads 48 | self.sthreads = sthreads 49 | self.espins = espins 50 | self.esleep = esleep 51 | self.sspins = sspins 52 | self.ssleep = ssleep 53 | self.disk_path = '' 54 | if not os.path.exists(iozone_path): 55 | raise RuntimeError("Benchmark executable not found. " + \ 56 | "Please run 'make -C tests iozone' before this script.") 57 | if is_debug_executable(iozone_path): 58 | raise RuntimeError("Will not run benchmarks on executable" +\ 59 | " compiled with DEBUG option"); 60 | self.iozone_cmd = iozone_path + ' -a -s{filesizek}k ' + \ 61 | '-r{recordsizek}k -i0 -i2' 62 | self.ramsize = 20*1024*1024 63 | 64 | def run(self): 65 | self.time_start = datetime.now() 66 | self.results = dict() 67 | self.env = os.environ.copy() 68 | self.env["MUSL_KERNEL"] = 0 69 | self.env["MUSL_RTPRIO"] = 0 70 | if self.root: 71 | if os.geteuid() != 0: 72 | raise RuntimeError("Must be run as root to use MUSL_KERNEL") 73 | self.env["MUSL_RTPRIO"] = 1 74 | self.iozone_cmd = 'nice -n -25 ' + self.iozone_cmd 75 | if self.kernel: 76 | if not os.path.exists(syscalldrv_path): 77 | raise RuntimeError("Please install a syscall driver") 78 | self.env["MUSL_KERNEL"] = 1 79 | self.env["MUSL_ETHREADS"] = self.ethreads 80 | self.env["MUSL_STHREADS"] = self.sthreads 81 | self.env["MUSL_ESPINS"] = self.espins 82 | self.env["MUSL_ESLEEP"] = self.esleep 83 | self.env["MUSL_SSPINS"] = self.sspins 84 | self.env["MUSL_SSLEEP"] = self.ssleep 85 | self.env["MUSL_NOLKL"] = 0 86 | self.env["MUSL_VERBOSELKL"] = 0 87 | self.env["MUSL_LKLRAM"] = self.ramsize 88 | self.env["MUSL_TAP"] = '' 89 | self.env["MUSL_HD"] = self.disk_path 90 | self.env = { k : str(v) for (k,v) in self.env.items() } 91 | for recordsize in self.recordsizes: 92 | read_results = [] 93 | write_results = [] 94 | iteration = 1 95 | errors = 0 96 | while iteration <= self.repeats: 97 | sys.stdout.write(' [*] Iteration %d/%d\r' % (iteration, 98 | self.repeats)) 99 | try: 100 | flush_caches() 101 | cmdline = self.iozone_cmd.format( 102 | filesizek = int(self.file_size/1024), 103 | recordsizek = recordsize, 104 | ) 105 | print(' [*] Running ' + cmdline) 106 | out = subprocess.check_output(cmdline.split(), 107 | universal_newlines=True, env=self.env, 108 | stderr=subprocess.STDOUT) 109 | match = re.search(r'^\s*kB.+\n.+\D(\d+)\s+(\d+)\s*$', out, 110 | flags=re.MULTILINE) 111 | if match is None: 112 | sys.stderr.write(' [!] Unable to parse result: %s\n' % out) 113 | errors += 1 114 | else: 115 | read = int(match.group(1))/1024 116 | write = int(match.group(2))/1024 117 | read_results.append(read) 118 | write_results.append(write) 119 | iteration += 1 120 | except subprocess.CalledProcessError as e: 121 | errors += 1 122 | if errors >= self.repeats: 123 | raise 124 | sys.stderr.write(' [!] Iteration %d/%d failed:\n%s\n%s\n' % 125 | (iteration, self.repeats, str(e), str(e.output))) 126 | read_mean = statistics.mean(read_results) 127 | write_mean = statistics.mean(write_results) 128 | read_rsd = 0 129 | write_rsd = 0 130 | if self.repeats >= 2: 131 | read_rsd = statistics.stdev(read_results)/read_mean 132 | write_rsd = statistics.stdev(write_results)/write_mean 133 | self.results[recordsize] = { 134 | "Record size (KiB)": recordsize, 135 | "Random reads (MiB/s)": read_mean, 136 | "Random writes (MiB/s)": write_mean, 137 | "Read RSD": read_rsd, 138 | "Write RSD": write_rsd, 139 | } 140 | sys.stdout.write((' [*] Record size %dKiB: R %.3f MiB/s (%.2f %%)' + \ 141 | ' W %.3f MiB/s (%.2f %%)\n') % (recordsize, read_mean, 142 | read_rsd*100, write_mean, write_rsd*100)) 143 | self.time_elapsed = datetime.now() - self.time_start 144 | with open(self.results_path, 'w') as final_results: 145 | final_results.truncate() 146 | fieldnames = ['Record size (KiB)','Random reads (MiB/s)', 147 | 'Random writes (MiB/s)','Read RSD', 'Write RSD'] 148 | writer = csv.DictWriter(final_results, fieldnames=fieldnames) 149 | writer.writeheader() 150 | for recordsize in self.recordsizes: 151 | writer.writerow(self.results[recordsize]) 152 | sys.stdout.write(' [*] Results written to %s\n' % 153 | self.results_path) 154 | 155 | class IOZoneTMPFSBenchmark(IOZoneBenchmark): 156 | 157 | def __init__(self, *args, **kwargs): 158 | super().__init__(*args, **kwargs) 159 | self.file_size = 1024*1024*1024 160 | self.ramsize += self.file_size 161 | self.results_path = 'iozone_results_tmpfs_%s_%s_%s_%dsamples.csv' %\ 162 | ("kernel" if self.kernel else "nokernel", 163 | "root" if self.root else "noroot", 164 | pretty_print_size(self.file_size), self.repeats) 165 | 166 | class IOZonePlainBenchmark(IOZoneBenchmark): 167 | 168 | def __init__(self, *args, **kwargs): 169 | super().__init__(*args, **kwargs) 170 | self.iozone_cmd += ' -f /largefile' 171 | self.disk_size = int((total_ram_bytes() * 2)/1024)*1024 172 | self.file_size = 1024*1024*1024 173 | self.disk_path = root_path + '/test_disk_plain.img' 174 | self.results_path = 'iozone_results_plain_%s_%s_%s_%dsamples.csv' %\ 175 | ("kernel" if self.kernel else "nokernel", 176 | "root" if self.root else "noroot", 177 | pretty_print_size(self.file_size), self.repeats) 178 | size = 0 179 | if os.path.isfile(self.disk_path): 180 | try: 181 | size = os.path.getsize(self.disk_path) 182 | except: 183 | pass 184 | if size != self.disk_size: 185 | os.unlink(self.disk_path) 186 | if size != self.disk_size: 187 | print(' [*] Creating test disk, this will take a while...') 188 | try: 189 | subprocess.check_call(['dd','if=/dev/zero','of=' + self.disk_path, 190 | 'bs=1k', 'count=' + str(int(self.disk_size/1024))], 191 | stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 192 | subprocess.check_call(['mkfs.ext4','-F',self.disk_path], 193 | stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 194 | except subprocess.CalledProcessError as e: 195 | raise RuntimeError("Unable to create benchmark disk:\n" + 196 | str(e) + '\n=====\n' + str(e.output)) 197 | 198 | class IOZoneEncryptionBenchmark(IOZoneBenchmark): 199 | 200 | def __init__(self, *args, **kwargs): 201 | super().__init__(*args, **kwargs) 202 | self.iozone_cmd += ' -f /largefile' 203 | self.disk_size = int((total_ram_bytes() * 2)/1024)*1024 204 | self.file_size = 1024*1024*1024 205 | self.disk_path = root_path + '/test_disk_encrypted.img' 206 | self.results_path = 'iozone_results_crypt_%s_%s_%s_%dsamples.csv' %\ 207 | ("kernel" if self.kernel else "nokernel", 208 | "root" if self.root else "noroot", 209 | pretty_print_size(self.file_size), self.repeats) 210 | size = 0 211 | if os.path.isfile(self.disk_path): 212 | try: 213 | size = os.path.getsize(self.disk_path) 214 | except: 215 | pass 216 | if size != self.disk_size: 217 | os.unlink(self.disk_path) 218 | if size != self.disk_size: 219 | print(' [*] Creating test disk (%d bytes, %s), this will take a while...' %\ 220 | (self.disk_size, pretty_print_size(self.disk_size))) 221 | try: 222 | subprocess.check_call(['dd','if=/dev/zero','of=%s.tmp' % self.disk_path, 223 | 'bs=1k', 'count=' + str(int(self.disk_size/1024))], 224 | stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 225 | subprocess.check_call(['mkfs.ext4','-F',self.disk_path + '.tmp'], 226 | stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 227 | subprocess.check_call([encrypt_tool_path, '-e', '-k', 228 | encrypt_default_key, '-i', self.disk_path + '.tmp', 229 | '-o', self.disk_path]) 230 | os.unlink(self.disk_path + '.tmp') 231 | except subprocess.CalledProcessError as e: 232 | raise RuntimeError("Unable to create benchmark disk:\n" + 233 | str(e) + '\n=====\n' + str(e.output)) 234 | 235 | if __name__ == '__main__': 236 | bench = IOZonePlainBenchmark(repeats=5, recordsizes=range(1,49)) 237 | bench.run() 238 | sys.stdout.write(' [*] Benchmark completed, total time %s\n' % 239 | pretty_print_duration(bench.time_elapsed)) 240 | 241 | -------------------------------------------------------------------------------- /tools/bench_memcached_throughput_latency.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | import time 6 | import statistics 7 | import matplotlib.pyplot as plt 8 | import csv 9 | from bench.benchmark import Benchmark 10 | from bench.utils import parse_timedelta, pretty_print_duration 11 | 12 | def bench_throughput_latency(samples=3, max_rsd=0.1, 13 | *args, **kwargs): 14 | while True: 15 | throughputs = [] 16 | latencies = [] 17 | iteration = 1 18 | errors = 0 19 | while iteration <= samples: 20 | sys.stdout.write(' [*] Iteration %d/%d\r' % (iteration,samples)) 21 | sys.stdout.flush() 22 | try: 23 | bench = Benchmark(*args, **kwargs) 24 | bench.run() 25 | throughputs.append(bench.throughput) 26 | latencies.append(bench.latency) 27 | iteration += 1 28 | except Exception as e: 29 | errors += 1 30 | if errors >= samples: 31 | raise 32 | print(' [!] Iteration %d failed: %s\n%s' % \ 33 | (iteration, str(type(e)), str(e))) 34 | mean_throughput = statistics.mean(throughputs) 35 | mean_latency = statistics.mean(latencies) 36 | stdev_throughput = statistics.stdev(throughputs) 37 | stdev_latency = statistics.stdev(latencies) 38 | rsd_throughput = stdev_throughput/mean_throughput 39 | rsd_latency = stdev_latency/mean_latency 40 | if rsd_throughput > max_rsd or rsd_latency > max_rsd: 41 | sys.stderr.write(' [!] Discarding experiment: '+\ 42 | 'throughput RSD %.2f %%, latency RSD %.2f %%\n' %\ 43 | (rsd_throughput*100, rsd_latency*100)) 44 | continue 45 | return (mean_throughput, mean_latency, 46 | rsd_throughput, rsd_latency) 47 | 48 | if __name__ == "__main__": 49 | samples = 5 50 | client_loads = range(1,16) 51 | max_rsd = 0.10 52 | type = Benchmark.TYPE_VANILLA 53 | ycsb = 'a' 54 | kernel = False 55 | throughput_vals = [] 56 | latency_vals = [] 57 | results = dict() 58 | if type == Benchmark.TYPE_VANILLA: 59 | espins, esleep, ssleep = 500, 16000, 4000 60 | else: 61 | espins, esleep, ssleep = 200, 14000, 8000 62 | for client_load in client_loads: 63 | throughput, latency, rsd_throughput, rsd_latency = \ 64 | bench_throughput_latency( 65 | clients=client_load, 66 | samples=samples, max_rsd=max_rsd, 67 | ycsb=ycsb, kernel=kernel, type=type, 68 | ethreads=4, sthreads=100, appthreads=2, slots=256, 69 | espins=espins, esleep=esleep, sspins=100, ssleep=ssleep 70 | ) 71 | results[client_load] = { 72 | "Clients": client_load, 73 | "Throughput": throughput, 74 | "Latency": latency, 75 | "Throughput RSD": rsd_throughput, 76 | "Latency RSD": rsd_latency, 77 | } 78 | print((' [*] %d clients | throughput %d (%.2f %% RSD) | ' + \ 79 | 'latency %d us (%.2f %% RSD)') % (client_load, throughput, 80 | rsd_throughput*100, latency, rsd_latency*100)) 81 | 82 | root_path = os.path.dirname(os.path.realpath(__file__)) 83 | csv_filename = "results_memcached_ycsb" + ycsb + "_" + \ 84 | ("" if kernel else "no") + "kernel_" + \ 85 | ("lkl" if type == Benchmark.TYPE_LKL else "vanilla") + \ 86 | "_" + str(samples) + "samples.csv" 87 | 88 | with open(root_path + '/' + csv_filename, 'w') as final_results: 89 | final_results.truncate() 90 | fieldnames = ['Clients','Throughput','Latency', 91 | 'Throughput RSD','Latency RSD'] 92 | writer = csv.DictWriter(final_results, fieldnames=fieldnames) 93 | writer.writeheader() 94 | for client_load in results: 95 | writer.writerow(results[client_load]) 96 | 97 | -------------------------------------------------------------------------------- /tools/bench_memcached_vanillaVSlkl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import time 5 | import statistics 6 | import matplotlib.pyplot as plt 7 | from bench.benchmark import Benchmark 8 | from bench.utils import parse_timedelta, pretty_print_duration 9 | 10 | def bench_throughput_latency(samples=sys.maxsize, duration=sys.maxsize, 11 | *args, **kwargs): 12 | throughputs = [] 13 | latencies = [] 14 | bench_start = time.time() 15 | iteration = 1 16 | errors = 0 17 | while (iteration <= samples and (time.time()-bench_start) < duration): 18 | sys.stdout.write(' [*] Iteration %d\r' % iteration) 19 | sys.stdout.flush() 20 | try: 21 | bench = Benchmark(*args, **kwargs) 22 | bench.run() 23 | throughputs.append(bench.throughput) 24 | latencies.append(bench.latency) 25 | iteration += 1 26 | except Exception as e: 27 | errors += 1 28 | if errors >= samples: 29 | raise 30 | print(' [!] Iteration %d failed: %s\n%s' % \ 31 | (iteration, str(type(e)), str(e))) 32 | print(' [*] Benchmark duration: %s (%d iterations)' % \ 33 | (pretty_print_duration(time.time() - bench_start), iteration-1)) 34 | return throughputs, latencies 35 | 36 | if __name__ == "__main__": 37 | if len(sys.argv) != 2: 38 | print('Usage: ./%s |' % sys.argv[0]) 39 | sys.exit(1) 40 | 41 | duration = parse_timedelta(sys.argv[1]) 42 | samples = sys.maxsize 43 | if duration is None: 44 | duration = sys.maxsize 45 | samples = int(sys.argv[1]) 46 | 47 | throughputs = dict() 48 | latencies = dict() 49 | for srv_type in (Benchmark.TYPE_VANILLA, Benchmark.TYPE_LKL): 50 | throughput_vals, latency_vals = \ 51 | bench_throughput_latency(ycsb='a', samples=samples, 52 | duration=duration, type=srv_type, clients=1, ethreads=4, 53 | sthreads=100, appthreads=2, slots=256, espins=200, 54 | esleep=14000, sspins=100, ssleep=8000) 55 | 56 | throughputs[srv_type] = statistics.mean(throughput_vals) 57 | latencies[srv_type] = statistics.mean(latency_vals) 58 | print(' [*] Results for %s:' % \ 59 | ('Vanilla' if srv_type == Benchmark.TYPE_VANILLA else 'LKL')) 60 | print(throughput_vals) 61 | print(latency_vals) 62 | print(' [*] Mean throughput: %.2f ops/s (RSD %.2f %%)' % 63 | (throughputs[srv_type], 64 | statistics.stdev(throughput_vals)/throughputs[srv_type]*100)) 65 | print(' [*] Mean latency: %.2f us (RSD %.2f %%)' % 66 | (latencies[srv_type], 67 | statistics.stdev(latency_vals)/latencies[srv_type]*100)) 68 | 69 | 70 | -------------------------------------------------------------------------------- /tools/disk_encrypt.c: -------------------------------------------------------------------------------- 1 | // 2 | // FAIR WARNING: 3 | // This is a proof of concept, written by a humble MSc student, probably 4 | // full of vulnerabilities and bugs. I'll be glad to fix them if you find 5 | // some, but please don't use this code in any production-like environment. 6 | // The fact that you give an encryption key as a command line argument 7 | // should be a pretty strong hint, but, hey, you never know. 8 | // 9 | 10 | #define _GNU_SOURCE 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #define DEFAULT_SECTOR_SIZE 512 22 | #define AES_KEY_LENGTH 32 23 | 24 | #define EVP_OR_GOTO_OUT(x) res = x; if (res != 1) { perror( #x ); goto out; } 25 | 26 | static volatile int interrupted = 0; 27 | 28 | typedef union aes_iv_plain64 { 29 | struct { 30 | uint64_t index; 31 | uint8_t zero_pad[AES_KEY_LENGTH-8]; 32 | } sector; 33 | unsigned char aes_iv[AES_KEY_LENGTH]; 34 | } aes_iv_plain64; 35 | 36 | typedef int (*blockdev_fn)(unsigned char*, int, unsigned char*, int*, 37 | uint64_t, unsigned char*); 38 | 39 | int blockdev_encrypt(unsigned char *plain_buf, int plain_len, 40 | unsigned char *cipher_buf, int *_cipher_len, uint64_t sector, 41 | unsigned char key[]) 42 | { 43 | aes_iv_plain64 iv; 44 | EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); 45 | int res = 1; 46 | int cipher_len = *_cipher_len; 47 | 48 | if (ctx == NULL) { 49 | perror("EVP_CIPHER_CTX_new()"); 50 | res = 1; 51 | goto out; 52 | } 53 | 54 | memset(&iv, 0, sizeof(iv)); 55 | iv.sector.index = htole64(sector); 56 | 57 | EVP_OR_GOTO_OUT(EVP_EncryptInit(ctx, EVP_aes_128_xts(), key, iv.aes_iv)) 58 | EVP_OR_GOTO_OUT(EVP_EncryptUpdate(ctx, cipher_buf, &cipher_len, plain_buf, plain_len)) 59 | int cipher_len_added = 0; 60 | EVP_OR_GOTO_OUT(EVP_EncryptFinal(ctx, cipher_buf + cipher_len, &cipher_len_added)) 61 | cipher_len += cipher_len_added; 62 | 63 | out: 64 | EVP_CIPHER_CTX_free(ctx); 65 | if (res == 1) 66 | *_cipher_len = cipher_len; 67 | return (res != 1); 68 | } 69 | 70 | int blockdev_decrypt(unsigned char *cipher_buf, int cipher_len, 71 | unsigned char *plain_buf, int *_plain_len, uint64_t sector, 72 | unsigned char key[]) 73 | { 74 | aes_iv_plain64 iv; 75 | EVP_CIPHER_CTX ctx; 76 | int res = 1; 77 | int plain_len = 0; 78 | 79 | memset(&iv, 0, sizeof(iv)); 80 | iv.sector.index = htole64(sector); 81 | 82 | EVP_OR_GOTO_OUT(EVP_DecryptInit(&ctx, EVP_aes_128_xts(), key, iv.aes_iv)) 83 | EVP_OR_GOTO_OUT(EVP_DecryptUpdate(&ctx, plain_buf, &plain_len, cipher_buf, cipher_len)) 84 | int plain_len_added = 0; 85 | EVP_OR_GOTO_OUT(EVP_DecryptFinal(&ctx, plain_buf + plain_len, &plain_len_added)) 86 | plain_len += plain_len_added; 87 | 88 | out: 89 | EVP_CIPHER_CTX_cleanup(&ctx); 90 | if (res == 1) 91 | *_plain_len = plain_len; 92 | return (res != 1); 93 | } 94 | 95 | void sig_handler(int signo) 96 | { 97 | if (signo != SIGINT) 98 | return; 99 | interrupted = 1; 100 | } 101 | 102 | void print_usage(const char* name) 103 | { 104 | fprintf(stderr, "Usage: %s [-e|-d] [-s sector_size] [-o output_file]" 105 | "[-i input file] -k encryption_key\n", name); 106 | exit(1); 107 | } 108 | 109 | int parse_key(const char *str, unsigned char key[]) 110 | { 111 | if (strlen(str) != 64) 112 | return 1; 113 | for (int i = 0; i < 32; i++) { 114 | int res = sscanf(str + 2*i, "%02x", (unsigned int*)&(key[i])); 115 | if (res != 1) 116 | return 2; 117 | } 118 | return 0; 119 | } 120 | 121 | int main(int argc, char* argv[]) 122 | { 123 | if (argc < 2) 124 | print_usage(argv[0]); 125 | 126 | int encrypting = -1; 127 | int sector_size = DEFAULT_SECTOR_SIZE; 128 | unsigned char aes_key[AES_KEY_LENGTH] = {0}; 129 | FILE *in = stdin; 130 | FILE *out = stdout; 131 | int c, res, i; 132 | while ((c = getopt(argc, argv, "edi:o:k:s:")) != -1) { 133 | if ((c == 'e' && encrypting == 0) || (c == 'd' && encrypting == 1)) { 134 | fprintf(stderr, "Error: conflicting -e/-d options\n"); 135 | print_usage(argv[0]); 136 | } 137 | switch (c) { 138 | case 'e': 139 | encrypting = 1; 140 | break; 141 | case 'd': 142 | encrypting = 0; 143 | break; 144 | case 'i': 145 | in = fopen(optarg, "rb"); 146 | if (in == NULL) { 147 | fprintf(stderr, "Error: unable to open %s\n", 148 | optarg); 149 | perror("fopen()"); 150 | return errno; 151 | } 152 | break; 153 | case 'o': 154 | out = fopen(optarg, "wb"); 155 | if (out == NULL) { 156 | fprintf(stderr, "Error: unable to open %s\n", 157 | optarg); 158 | perror("fopen()"); 159 | return errno; 160 | } 161 | break; 162 | case 'k': 163 | res = parse_key(optarg, aes_key); 164 | if (res != 0) { 165 | fprintf(stderr, "Invalid key format, use " 166 | "a 64-char hexadecimal string\n"); 167 | print_usage(argv[0]); 168 | return res; 169 | } 170 | break; 171 | case 's': 172 | sector_size = strtoul(optarg, NULL, 10); 173 | if (sector_size <= 1) { 174 | fprintf(stderr, "Invalid sector size\n"); 175 | print_usage(argv[0]); 176 | } 177 | default: 178 | print_usage(argv[0]); 179 | } 180 | } 181 | 182 | if (encrypting < 0) { 183 | fprintf(stderr, "Error: must specify an operation -e or -d\n"); 184 | print_usage(argv[0]); 185 | } 186 | blockdev_fn op = (encrypting ? &blockdev_encrypt : &blockdev_decrypt); 187 | for (i = 0; i < AES_KEY_LENGTH; i++) 188 | if (aes_key[i] != 0) 189 | break; 190 | if (i >= AES_KEY_LENGTH) { 191 | fprintf(stderr, "Error: no key or key=0 given\n"); 192 | print_usage(argv[0]); 193 | } 194 | 195 | if (signal(SIGINT, sig_handler) == SIG_ERR) 196 | fprintf(stderr, " [!] Can't catch SIGINTs\n"); 197 | 198 | unsigned char *readbuf = (unsigned char*)calloc(1, sector_size); 199 | unsigned char *writebuf = (unsigned char*)calloc(1, sector_size); 200 | if (readbuf == NULL || writebuf == NULL) 201 | return ENOMEM; 202 | 203 | time_t start = time(NULL); 204 | uint64_t sector; 205 | for (sector = 0; !interrupted; sector++) { 206 | int read = (int)fread(readbuf, 1, sector_size, in); 207 | if (read != sector_size) { 208 | if (ferror(in) || (!encrypting && read != 0)) { 209 | fprintf(stderr, " [!] I/O error: %d bytes " 210 | "returned, error %d\n", read, errno); 211 | res = 4; 212 | break; 213 | } 214 | else if (encrypting && read > 0) { 215 | fprintf(stderr, " [*] Last block was %d bytes," 216 | " 0-padding to %d bytes\n", read, 217 | (int)sector_size); 218 | for (int i = read; i < sector_size; i++) 219 | readbuf[i] = 0; 220 | } else { 221 | break; 222 | } 223 | } 224 | int handled = sector_size; 225 | res = op(readbuf, sector_size, writebuf, &handled, sector, aes_key); 226 | if (res != 0 || handled != sector_size) { 227 | fprintf(stderr, "Error: %s code %d at sector %llu\n", 228 | (encrypting ? "encryption" : "decryption"), 229 | res, (unsigned long long)sector); 230 | break; 231 | } 232 | int written = fwrite(writebuf, 1, sector_size, out); 233 | if (written != sector_size) { 234 | fprintf(stderr, "Error: I/O failed while writing\n"); 235 | res = errno; 236 | break; 237 | } 238 | if (read != sector_size) 239 | break; 240 | } 241 | 242 | if (res != 0) 243 | fprintf(stderr, " [!] Error code %d\n", res); 244 | if (interrupted) 245 | fprintf(stderr, " [!] Received SIGINT, stopping\n"); 246 | 247 | unsigned long duration = time(NULL) - start; 248 | fprintf(stderr, " [+] %lld bytes written in %ld seconds (%.3f MiB/s)\n", 249 | (unsigned long long)(sector*sector_size), duration, 250 | ((double)sector*sector_size)/(duration*1024*1024)); 251 | 252 | if (out != stdout) 253 | fclose(out); 254 | if (in != stdin) 255 | fclose(in); 256 | return res; 257 | } 258 | -------------------------------------------------------------------------------- /tools/lkl_bits.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define str(s) #s 6 | #define EXPORT_LKL_SYSCALL(name) \ 7 | printf("#undef __NR_" str(name) "\n"); \ 8 | printf("#undef SYS_" str(name) "\n"); \ 9 | printf("#define __NR_" str(name) " %d\n", (__lkl__NR_ ## name)); \ 10 | printf("#define SYS_" str(name) " __NR_" str(name) "\n"); 11 | 12 | #define EXPORT_HOST_SYSCALL(name) \ 13 | printf("#undef __NR_" str(name) "\n"); \ 14 | printf("#undef SYS_" str(name) "\n"); \ 15 | printf("#define __NR_" str(name) " %d\n", (__lkl__NR_arch_specific_syscall + __COUNTER__)); \ 16 | printf("#define SYS_" str(name) " __NR_" str(name) "\n"); 17 | 18 | int main() { 19 | printf("// Generated using tools/lkl_bits.c , changes will be overwritten\n\n"); 20 | printf("#ifndef __INCLUDE_FROM_SYS_SYSCALL_H\n"); 21 | printf("#error \"Please do not include lkl/syscall.h directly.\"\n"); 22 | printf("#endif\n"); 23 | EXPORT_LKL_SYSCALL(accept) 24 | EXPORT_LKL_SYSCALL(accept4) 25 | EXPORT_LKL_SYSCALL(access) 26 | EXPORT_LKL_SYSCALL(acct) 27 | EXPORT_LKL_SYSCALL(add_key) 28 | EXPORT_LKL_SYSCALL(adjtimex) 29 | EXPORT_LKL_SYSCALL(alarm) 30 | EXPORT_LKL_SYSCALL(bdflush) 31 | EXPORT_LKL_SYSCALL(bind) 32 | EXPORT_LKL_SYSCALL(bpf) 33 | EXPORT_LKL_SYSCALL(brk) 34 | EXPORT_LKL_SYSCALL(capget) 35 | EXPORT_LKL_SYSCALL(capset) 36 | EXPORT_LKL_SYSCALL(chdir) 37 | EXPORT_LKL_SYSCALL(chmod) 38 | EXPORT_LKL_SYSCALL(chown) 39 | EXPORT_LKL_SYSCALL(chroot) 40 | EXPORT_LKL_SYSCALL(clock_adjtime) 41 | EXPORT_LKL_SYSCALL(clock_getres) 42 | EXPORT_LKL_SYSCALL(clock_gettime) 43 | EXPORT_LKL_SYSCALL(clock_nanosleep) 44 | EXPORT_LKL_SYSCALL(clock_settime) 45 | EXPORT_LKL_SYSCALL(clone) 46 | EXPORT_LKL_SYSCALL(close) 47 | EXPORT_LKL_SYSCALL(connect) 48 | EXPORT_LKL_SYSCALL(copy_file_range) 49 | EXPORT_LKL_SYSCALL(creat) 50 | EXPORT_LKL_SYSCALL(delete_module) 51 | EXPORT_LKL_SYSCALL(dup) 52 | EXPORT_LKL_SYSCALL(dup2) 53 | EXPORT_LKL_SYSCALL(dup3) 54 | EXPORT_LKL_SYSCALL(epoll_create) 55 | EXPORT_LKL_SYSCALL(epoll_create1) 56 | EXPORT_LKL_SYSCALL(epoll_ctl) 57 | EXPORT_LKL_SYSCALL(epoll_pwait) 58 | EXPORT_LKL_SYSCALL(epoll_wait) 59 | EXPORT_LKL_SYSCALL(eventfd) 60 | EXPORT_LKL_SYSCALL(eventfd2) 61 | EXPORT_LKL_SYSCALL(execve) 62 | EXPORT_LKL_SYSCALL(execveat) 63 | EXPORT_LKL_SYSCALL(exit) 64 | EXPORT_LKL_SYSCALL(exit_group) 65 | EXPORT_LKL_SYSCALL(faccessat) 66 | EXPORT_LKL_SYSCALL(fadvise64) 67 | EXPORT_LKL_SYSCALL(fallocate) 68 | EXPORT_LKL_SYSCALL(fanotify_init) 69 | EXPORT_LKL_SYSCALL(fanotify_mark) 70 | EXPORT_LKL_SYSCALL(fchdir) 71 | EXPORT_LKL_SYSCALL(fchmod) 72 | EXPORT_LKL_SYSCALL(fchmodat) 73 | EXPORT_LKL_SYSCALL(fchown) 74 | EXPORT_LKL_SYSCALL(fchownat) 75 | EXPORT_LKL_SYSCALL(fcntl) 76 | EXPORT_LKL_SYSCALL(fdatasync) 77 | EXPORT_LKL_SYSCALL(fgetxattr) 78 | EXPORT_LKL_SYSCALL(finit_module) 79 | EXPORT_LKL_SYSCALL(flistxattr) 80 | EXPORT_LKL_SYSCALL(flock) 81 | EXPORT_LKL_SYSCALL(fork) 82 | EXPORT_LKL_SYSCALL(fremovexattr) 83 | EXPORT_LKL_SYSCALL(fsetxattr) 84 | EXPORT_LKL_SYSCALL(fstat) 85 | EXPORT_LKL_SYSCALL(fstatfs) 86 | EXPORT_LKL_SYSCALL(fsync) 87 | EXPORT_LKL_SYSCALL(ftruncate) 88 | EXPORT_LKL_SYSCALL(futex) 89 | EXPORT_LKL_SYSCALL(futimesat) 90 | EXPORT_LKL_SYSCALL(getcwd) 91 | EXPORT_LKL_SYSCALL(getdents) 92 | EXPORT_LKL_SYSCALL(getdents64) 93 | EXPORT_LKL_SYSCALL(getegid) 94 | EXPORT_LKL_SYSCALL(geteuid) 95 | EXPORT_LKL_SYSCALL(getgid) 96 | EXPORT_LKL_SYSCALL(getgroups) 97 | EXPORT_LKL_SYSCALL(getitimer) 98 | EXPORT_LKL_SYSCALL(get_mempolicy) 99 | EXPORT_LKL_SYSCALL(getpeername) 100 | EXPORT_LKL_SYSCALL(getpgid) 101 | EXPORT_LKL_SYSCALL(getpgrp) 102 | EXPORT_LKL_SYSCALL(getpid) 103 | EXPORT_LKL_SYSCALL(getppid) 104 | EXPORT_LKL_SYSCALL(getpriority) 105 | EXPORT_LKL_SYSCALL(getrandom) 106 | EXPORT_LKL_SYSCALL(getresgid) 107 | EXPORT_LKL_SYSCALL(getresuid) 108 | EXPORT_LKL_SYSCALL(getrlimit) 109 | EXPORT_LKL_SYSCALL(get_robust_list) 110 | EXPORT_LKL_SYSCALL(getrusage) 111 | EXPORT_LKL_SYSCALL(getsid) 112 | EXPORT_LKL_SYSCALL(getsockname) 113 | EXPORT_LKL_SYSCALL(getsockopt) 114 | EXPORT_LKL_SYSCALL(gettid) 115 | EXPORT_LKL_SYSCALL(gettimeofday) 116 | EXPORT_LKL_SYSCALL(getuid) 117 | EXPORT_LKL_SYSCALL(getxattr) 118 | EXPORT_LKL_SYSCALL(init_module) 119 | EXPORT_LKL_SYSCALL(inotify_add_watch) 120 | EXPORT_LKL_SYSCALL(inotify_init) 121 | EXPORT_LKL_SYSCALL(inotify_init1) 122 | EXPORT_LKL_SYSCALL(inotify_rm_watch) 123 | EXPORT_LKL_SYSCALL(io_cancel) 124 | EXPORT_LKL_SYSCALL(ioctl) 125 | EXPORT_LKL_SYSCALL(io_destroy) 126 | EXPORT_LKL_SYSCALL(io_getevents) 127 | EXPORT_LKL_SYSCALL(ioprio_get) 128 | EXPORT_LKL_SYSCALL(ioprio_set) 129 | EXPORT_LKL_SYSCALL(io_setup) 130 | EXPORT_LKL_SYSCALL(io_submit) 131 | EXPORT_LKL_SYSCALL(kcmp) 132 | EXPORT_LKL_SYSCALL(keyctl) 133 | EXPORT_LKL_SYSCALL(kill) 134 | EXPORT_LKL_SYSCALL(lchown) 135 | EXPORT_LKL_SYSCALL(lgetxattr) 136 | EXPORT_LKL_SYSCALL(link) 137 | EXPORT_LKL_SYSCALL(linkat) 138 | EXPORT_LKL_SYSCALL(listen) 139 | EXPORT_LKL_SYSCALL(listxattr) 140 | EXPORT_LKL_SYSCALL(llistxattr) 141 | EXPORT_LKL_SYSCALL(lookup_dcookie) 142 | EXPORT_LKL_SYSCALL(lremovexattr) 143 | EXPORT_LKL_SYSCALL(lseek) 144 | EXPORT_LKL_SYSCALL(lsetxattr) 145 | EXPORT_LKL_SYSCALL(lstat) 146 | EXPORT_LKL_SYSCALL(madvise) 147 | EXPORT_LKL_SYSCALL(mbind) 148 | EXPORT_LKL_SYSCALL(membarrier) 149 | EXPORT_LKL_SYSCALL(memfd_create) 150 | EXPORT_LKL_SYSCALL(migrate_pages) 151 | EXPORT_LKL_SYSCALL(mincore) 152 | EXPORT_LKL_SYSCALL(mkdir) 153 | EXPORT_LKL_SYSCALL(mkdirat) 154 | EXPORT_LKL_SYSCALL(mknod) 155 | EXPORT_LKL_SYSCALL(mknodat) 156 | EXPORT_LKL_SYSCALL(mlock) 157 | EXPORT_LKL_SYSCALL(mlock2) 158 | EXPORT_LKL_SYSCALL(mlockall) 159 | EXPORT_LKL_SYSCALL(mmap) 160 | EXPORT_LKL_SYSCALL(mount) 161 | EXPORT_LKL_SYSCALL(move_pages) 162 | EXPORT_LKL_SYSCALL(mprotect) 163 | EXPORT_LKL_SYSCALL(mq_getsetattr) 164 | EXPORT_LKL_SYSCALL(mq_notify) 165 | EXPORT_LKL_SYSCALL(mq_open) 166 | EXPORT_LKL_SYSCALL(mq_timedreceive) 167 | EXPORT_LKL_SYSCALL(mq_timedsend) 168 | EXPORT_LKL_SYSCALL(mq_unlink) 169 | EXPORT_LKL_SYSCALL(mremap) 170 | EXPORT_LKL_SYSCALL(msgctl) 171 | EXPORT_LKL_SYSCALL(msgget) 172 | EXPORT_LKL_SYSCALL(msgrcv) 173 | EXPORT_LKL_SYSCALL(msgsnd) 174 | EXPORT_LKL_SYSCALL(msync) 175 | EXPORT_LKL_SYSCALL(munlock) 176 | EXPORT_LKL_SYSCALL(munlockall) 177 | EXPORT_LKL_SYSCALL(munmap) 178 | EXPORT_LKL_SYSCALL(nanosleep) 179 | EXPORT_LKL_SYSCALL(newfstatat) 180 | EXPORT_LKL_SYSCALL(nfsservctl) 181 | EXPORT_LKL_SYSCALL(oldwait4) 182 | EXPORT_LKL_SYSCALL(open) 183 | EXPORT_LKL_SYSCALL(openat) 184 | EXPORT_LKL_SYSCALL(pause) 185 | EXPORT_LKL_SYSCALL(perf_event_open) 186 | EXPORT_LKL_SYSCALL(personality) 187 | EXPORT_LKL_SYSCALL(pipe) 188 | EXPORT_LKL_SYSCALL(pipe2) 189 | EXPORT_LKL_SYSCALL(pivot_root) 190 | EXPORT_LKL_SYSCALL(poll) 191 | EXPORT_LKL_SYSCALL(ppoll) 192 | EXPORT_LKL_SYSCALL(prctl) 193 | EXPORT_LKL_SYSCALL(pread64) 194 | EXPORT_LKL_SYSCALL(preadv) 195 | EXPORT_LKL_SYSCALL(preadv2) 196 | EXPORT_LKL_SYSCALL(prlimit64) 197 | EXPORT_LKL_SYSCALL(process_vm_readv) 198 | EXPORT_LKL_SYSCALL(process_vm_writev) 199 | EXPORT_LKL_SYSCALL(pselect6) 200 | EXPORT_LKL_SYSCALL(ptrace) 201 | EXPORT_LKL_SYSCALL(pwrite64) 202 | EXPORT_LKL_SYSCALL(pwritev) 203 | EXPORT_LKL_SYSCALL(pwritev2) 204 | EXPORT_LKL_SYSCALL(quotactl) 205 | EXPORT_LKL_SYSCALL(read) 206 | EXPORT_LKL_SYSCALL(readahead) 207 | EXPORT_LKL_SYSCALL(readlink) 208 | EXPORT_LKL_SYSCALL(readlinkat) 209 | EXPORT_LKL_SYSCALL(readv) 210 | EXPORT_LKL_SYSCALL(reboot) 211 | EXPORT_LKL_SYSCALL(recv) 212 | EXPORT_LKL_SYSCALL(recvfrom) 213 | EXPORT_LKL_SYSCALL(recvmmsg) 214 | EXPORT_LKL_SYSCALL(recvmsg) 215 | EXPORT_LKL_SYSCALL(remap_file_pages) 216 | EXPORT_LKL_SYSCALL(removexattr) 217 | EXPORT_LKL_SYSCALL(rename) 218 | EXPORT_LKL_SYSCALL(renameat) 219 | EXPORT_LKL_SYSCALL(renameat2) 220 | EXPORT_LKL_SYSCALL(request_key) 221 | EXPORT_LKL_SYSCALL(restart_syscall) 222 | EXPORT_LKL_SYSCALL(rmdir) 223 | EXPORT_LKL_SYSCALL(rt_sigaction) 224 | EXPORT_LKL_SYSCALL(rt_sigpending) 225 | EXPORT_LKL_SYSCALL(rt_sigprocmask) 226 | EXPORT_LKL_SYSCALL(rt_sigqueueinfo) 227 | EXPORT_LKL_SYSCALL(rt_sigreturn) 228 | EXPORT_LKL_SYSCALL(rt_sigsuspend) 229 | EXPORT_LKL_SYSCALL(rt_sigtimedwait) 230 | EXPORT_LKL_SYSCALL(rt_tgsigqueueinfo) 231 | EXPORT_LKL_SYSCALL(sched_getaffinity) 232 | EXPORT_LKL_SYSCALL(sched_get_priority_max) 233 | EXPORT_LKL_SYSCALL(sched_get_priority_min) 234 | EXPORT_LKL_SYSCALL(sched_getscheduler) 235 | EXPORT_LKL_SYSCALL(sched_rr_get_interval) 236 | EXPORT_LKL_SYSCALL(sched_setaffinity) 237 | EXPORT_LKL_SYSCALL(sched_yield) 238 | EXPORT_LKL_SYSCALL(seccomp) 239 | EXPORT_LKL_SYSCALL(select) 240 | EXPORT_LKL_SYSCALL(semctl) 241 | EXPORT_LKL_SYSCALL(semget) 242 | EXPORT_LKL_SYSCALL(semop) 243 | EXPORT_LKL_SYSCALL(semtimedop) 244 | EXPORT_LKL_SYSCALL(send) 245 | EXPORT_LKL_SYSCALL(sendfile) 246 | EXPORT_LKL_SYSCALL(sendmmsg) 247 | EXPORT_LKL_SYSCALL(sendmsg) 248 | EXPORT_LKL_SYSCALL(sendto) 249 | EXPORT_LKL_SYSCALL(setdomainname) 250 | EXPORT_LKL_SYSCALL(setfsgid) 251 | EXPORT_LKL_SYSCALL(setfsuid) 252 | EXPORT_LKL_SYSCALL(setgid) 253 | EXPORT_LKL_SYSCALL(setgroups) 254 | EXPORT_LKL_SYSCALL(sethostname) 255 | EXPORT_LKL_SYSCALL(setitimer) 256 | EXPORT_LKL_SYSCALL(set_mempolicy) 257 | EXPORT_LKL_SYSCALL(setns) 258 | EXPORT_LKL_SYSCALL(setpgid) 259 | EXPORT_LKL_SYSCALL(setpriority) 260 | EXPORT_LKL_SYSCALL(setregid) 261 | EXPORT_LKL_SYSCALL(setresgid) 262 | EXPORT_LKL_SYSCALL(setresuid) 263 | EXPORT_LKL_SYSCALL(setreuid) 264 | EXPORT_LKL_SYSCALL(setrlimit) 265 | EXPORT_LKL_SYSCALL(set_robust_list) 266 | EXPORT_LKL_SYSCALL(setsid) 267 | EXPORT_LKL_SYSCALL(setsockopt) 268 | EXPORT_LKL_SYSCALL(set_tid_address) 269 | EXPORT_LKL_SYSCALL(settimeofday) 270 | EXPORT_LKL_SYSCALL(setuid) 271 | EXPORT_LKL_SYSCALL(setxattr) 272 | EXPORT_LKL_SYSCALL(shmat) 273 | EXPORT_LKL_SYSCALL(shmctl) 274 | EXPORT_LKL_SYSCALL(shmdt) 275 | EXPORT_LKL_SYSCALL(shmget) 276 | EXPORT_LKL_SYSCALL(shutdown) 277 | EXPORT_LKL_SYSCALL(sigaltstack) 278 | EXPORT_LKL_SYSCALL(signalfd) 279 | EXPORT_LKL_SYSCALL(signalfd4) 280 | EXPORT_LKL_SYSCALL(socket) 281 | EXPORT_LKL_SYSCALL(socketpair) 282 | EXPORT_LKL_SYSCALL(splice) 283 | EXPORT_LKL_SYSCALL(stat) 284 | EXPORT_LKL_SYSCALL(statfs) 285 | EXPORT_LKL_SYSCALL(swapoff) 286 | EXPORT_LKL_SYSCALL(swapon) 287 | EXPORT_LKL_SYSCALL(symlink) 288 | EXPORT_LKL_SYSCALL(symlinkat) 289 | EXPORT_LKL_SYSCALL(sync) 290 | EXPORT_LKL_SYSCALL(sync_file_range) 291 | EXPORT_LKL_SYSCALL(syncfs) 292 | EXPORT_LKL_SYSCALL(syscalls) 293 | EXPORT_LKL_SYSCALL(_sysctl) 294 | EXPORT_LKL_SYSCALL(sysinfo) 295 | EXPORT_LKL_SYSCALL(syslog) 296 | EXPORT_LKL_SYSCALL(tee) 297 | EXPORT_LKL_SYSCALL(tgkill) 298 | EXPORT_LKL_SYSCALL(time) 299 | EXPORT_LKL_SYSCALL(timer_create) 300 | EXPORT_LKL_SYSCALL(timer_delete) 301 | EXPORT_LKL_SYSCALL(timerfd_create) 302 | EXPORT_LKL_SYSCALL(timerfd_gettime) 303 | EXPORT_LKL_SYSCALL(timerfd_settime) 304 | EXPORT_LKL_SYSCALL(timer_getoverrun) 305 | EXPORT_LKL_SYSCALL(timer_gettime) 306 | EXPORT_LKL_SYSCALL(timer_settime) 307 | EXPORT_LKL_SYSCALL(times) 308 | EXPORT_LKL_SYSCALL(tkill) 309 | EXPORT_LKL_SYSCALL(truncate) 310 | EXPORT_LKL_SYSCALL(umask) 311 | EXPORT_LKL_SYSCALL(umount) 312 | EXPORT_LKL_SYSCALL(umount2) 313 | EXPORT_LKL_SYSCALL(uname) 314 | EXPORT_LKL_SYSCALL(unlink) 315 | EXPORT_LKL_SYSCALL(unlinkat) 316 | EXPORT_LKL_SYSCALL(unshare) 317 | EXPORT_LKL_SYSCALL(uselib) 318 | EXPORT_LKL_SYSCALL(userfaultfd) 319 | EXPORT_LKL_SYSCALL(ustat) 320 | EXPORT_LKL_SYSCALL(utime) 321 | EXPORT_LKL_SYSCALL(utimensat) 322 | EXPORT_LKL_SYSCALL(utimes) 323 | EXPORT_LKL_SYSCALL(vfork) 324 | EXPORT_LKL_SYSCALL(vhangup) 325 | EXPORT_LKL_SYSCALL(vmsplice) 326 | EXPORT_LKL_SYSCALL(wait4) 327 | EXPORT_LKL_SYSCALL(waitid) 328 | EXPORT_LKL_SYSCALL(write) 329 | EXPORT_LKL_SYSCALL(writev) 330 | 331 | EXPORT_HOST_SYSCALL(arch_prctl) 332 | EXPORT_HOST_SYSCALL(iopl) 333 | EXPORT_HOST_SYSCALL(ioperm) 334 | EXPORT_HOST_SYSCALL(getcpu) 335 | 336 | return 0; 337 | } 338 | -------------------------------------------------------------------------------- /tools/lkl_syscalls.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define str(s) #s 6 | #define EXPORT_LKL_SYSCALL(name) \ 7 | printf("__LKL_SYSCALL(" str(name) ")\n"); 8 | 9 | #define EXPORT_HOST_SYSCALL(name) \ 10 | printf("#define __lkl__NR_" str(name) " __lkl__NR_syscalls+%d\n", __COUNTER__); \ 11 | printf("__LKL_SYSCALL(" str(name) ")\n"); 12 | 13 | int main() { 14 | printf("// Generated using tools/lkl_syscalls.c , changes will be overwritten\n\n"); 15 | printf("#ifndef __LKL_SYSCALL\n"); 16 | printf("#define __LKL_SYSCALL(name) \n"); 17 | printf("#endif\n\n"); 18 | EXPORT_LKL_SYSCALL(accept) 19 | EXPORT_LKL_SYSCALL(accept4) 20 | EXPORT_LKL_SYSCALL(access) 21 | EXPORT_LKL_SYSCALL(acct) 22 | EXPORT_LKL_SYSCALL(add_key) 23 | EXPORT_LKL_SYSCALL(adjtimex) 24 | EXPORT_LKL_SYSCALL(alarm) 25 | EXPORT_LKL_SYSCALL(bdflush) 26 | EXPORT_LKL_SYSCALL(bind) 27 | EXPORT_LKL_SYSCALL(bpf) 28 | EXPORT_LKL_SYSCALL(brk) 29 | EXPORT_LKL_SYSCALL(capget) 30 | EXPORT_LKL_SYSCALL(capset) 31 | EXPORT_LKL_SYSCALL(chdir) 32 | EXPORT_LKL_SYSCALL(chmod) 33 | EXPORT_LKL_SYSCALL(chown) 34 | EXPORT_LKL_SYSCALL(chroot) 35 | EXPORT_LKL_SYSCALL(clock_adjtime) 36 | EXPORT_LKL_SYSCALL(clock_getres) 37 | EXPORT_LKL_SYSCALL(clock_gettime) 38 | EXPORT_LKL_SYSCALL(clock_nanosleep) 39 | EXPORT_LKL_SYSCALL(clock_settime) 40 | EXPORT_LKL_SYSCALL(clone) 41 | EXPORT_LKL_SYSCALL(close) 42 | EXPORT_LKL_SYSCALL(connect) 43 | EXPORT_LKL_SYSCALL(copy_file_range) 44 | EXPORT_LKL_SYSCALL(creat) 45 | EXPORT_LKL_SYSCALL(delete_module) 46 | EXPORT_LKL_SYSCALL(dup) 47 | EXPORT_LKL_SYSCALL(dup2) 48 | EXPORT_LKL_SYSCALL(dup3) 49 | EXPORT_LKL_SYSCALL(epoll_create) 50 | EXPORT_LKL_SYSCALL(epoll_create1) 51 | EXPORT_LKL_SYSCALL(epoll_ctl) 52 | EXPORT_LKL_SYSCALL(epoll_pwait) 53 | EXPORT_LKL_SYSCALL(epoll_wait) 54 | EXPORT_LKL_SYSCALL(eventfd) 55 | EXPORT_LKL_SYSCALL(eventfd2) 56 | EXPORT_LKL_SYSCALL(execve) 57 | EXPORT_LKL_SYSCALL(execveat) 58 | EXPORT_LKL_SYSCALL(exit) 59 | EXPORT_LKL_SYSCALL(exit_group) 60 | EXPORT_LKL_SYSCALL(faccessat) 61 | EXPORT_LKL_SYSCALL(fadvise64) 62 | EXPORT_LKL_SYSCALL(fallocate) 63 | EXPORT_LKL_SYSCALL(fanotify_init) 64 | EXPORT_LKL_SYSCALL(fanotify_mark) 65 | EXPORT_LKL_SYSCALL(fchdir) 66 | EXPORT_LKL_SYSCALL(fchmod) 67 | EXPORT_LKL_SYSCALL(fchmodat) 68 | EXPORT_LKL_SYSCALL(fchown) 69 | EXPORT_LKL_SYSCALL(fchownat) 70 | EXPORT_LKL_SYSCALL(fcntl) 71 | EXPORT_LKL_SYSCALL(fdatasync) 72 | EXPORT_LKL_SYSCALL(fgetxattr) 73 | EXPORT_LKL_SYSCALL(finit_module) 74 | EXPORT_LKL_SYSCALL(flistxattr) 75 | EXPORT_LKL_SYSCALL(flock) 76 | EXPORT_LKL_SYSCALL(fork) 77 | EXPORT_LKL_SYSCALL(fremovexattr) 78 | EXPORT_LKL_SYSCALL(fsetxattr) 79 | EXPORT_LKL_SYSCALL(fstat) 80 | EXPORT_LKL_SYSCALL(fstatfs) 81 | EXPORT_LKL_SYSCALL(fsync) 82 | EXPORT_LKL_SYSCALL(ftruncate) 83 | EXPORT_LKL_SYSCALL(futex) 84 | EXPORT_LKL_SYSCALL(futimesat) 85 | EXPORT_LKL_SYSCALL(getcwd) 86 | EXPORT_LKL_SYSCALL(getdents) 87 | EXPORT_LKL_SYSCALL(getdents64) 88 | EXPORT_LKL_SYSCALL(getegid) 89 | EXPORT_LKL_SYSCALL(geteuid) 90 | EXPORT_LKL_SYSCALL(getgid) 91 | EXPORT_LKL_SYSCALL(getgroups) 92 | EXPORT_LKL_SYSCALL(getitimer) 93 | EXPORT_LKL_SYSCALL(get_mempolicy) 94 | EXPORT_LKL_SYSCALL(getpeername) 95 | EXPORT_LKL_SYSCALL(getpgid) 96 | EXPORT_LKL_SYSCALL(getpgrp) 97 | EXPORT_LKL_SYSCALL(getpid) 98 | EXPORT_LKL_SYSCALL(getppid) 99 | EXPORT_LKL_SYSCALL(getpriority) 100 | EXPORT_LKL_SYSCALL(getrandom) 101 | EXPORT_LKL_SYSCALL(getresgid) 102 | EXPORT_LKL_SYSCALL(getresuid) 103 | EXPORT_LKL_SYSCALL(getrlimit) 104 | EXPORT_LKL_SYSCALL(get_robust_list) 105 | EXPORT_LKL_SYSCALL(getrusage) 106 | EXPORT_LKL_SYSCALL(getsid) 107 | EXPORT_LKL_SYSCALL(getsockname) 108 | EXPORT_LKL_SYSCALL(getsockopt) 109 | EXPORT_LKL_SYSCALL(gettid) 110 | EXPORT_LKL_SYSCALL(gettimeofday) 111 | EXPORT_LKL_SYSCALL(getuid) 112 | EXPORT_LKL_SYSCALL(getxattr) 113 | EXPORT_LKL_SYSCALL(init_module) 114 | EXPORT_LKL_SYSCALL(inotify_add_watch) 115 | EXPORT_LKL_SYSCALL(inotify_init) 116 | EXPORT_LKL_SYSCALL(inotify_init1) 117 | EXPORT_LKL_SYSCALL(inotify_rm_watch) 118 | EXPORT_LKL_SYSCALL(io_cancel) 119 | EXPORT_LKL_SYSCALL(ioctl) 120 | EXPORT_LKL_SYSCALL(io_destroy) 121 | EXPORT_LKL_SYSCALL(io_getevents) 122 | EXPORT_LKL_SYSCALL(ioprio_get) 123 | EXPORT_LKL_SYSCALL(ioprio_set) 124 | EXPORT_LKL_SYSCALL(io_setup) 125 | EXPORT_LKL_SYSCALL(io_submit) 126 | EXPORT_LKL_SYSCALL(kcmp) 127 | EXPORT_LKL_SYSCALL(keyctl) 128 | EXPORT_LKL_SYSCALL(kill) 129 | EXPORT_LKL_SYSCALL(lchown) 130 | EXPORT_LKL_SYSCALL(lgetxattr) 131 | EXPORT_LKL_SYSCALL(link) 132 | EXPORT_LKL_SYSCALL(linkat) 133 | EXPORT_LKL_SYSCALL(listen) 134 | EXPORT_LKL_SYSCALL(listxattr) 135 | EXPORT_LKL_SYSCALL(llistxattr) 136 | EXPORT_LKL_SYSCALL(lookup_dcookie) 137 | EXPORT_LKL_SYSCALL(lremovexattr) 138 | EXPORT_LKL_SYSCALL(lseek) 139 | EXPORT_LKL_SYSCALL(lsetxattr) 140 | EXPORT_LKL_SYSCALL(lstat) 141 | EXPORT_LKL_SYSCALL(madvise) 142 | EXPORT_LKL_SYSCALL(mbind) 143 | EXPORT_LKL_SYSCALL(membarrier) 144 | EXPORT_LKL_SYSCALL(memfd_create) 145 | EXPORT_LKL_SYSCALL(migrate_pages) 146 | EXPORT_LKL_SYSCALL(mincore) 147 | EXPORT_LKL_SYSCALL(mkdir) 148 | EXPORT_LKL_SYSCALL(mkdirat) 149 | EXPORT_LKL_SYSCALL(mknod) 150 | EXPORT_LKL_SYSCALL(mknodat) 151 | EXPORT_LKL_SYSCALL(mlock) 152 | EXPORT_LKL_SYSCALL(mlock2) 153 | EXPORT_LKL_SYSCALL(mlockall) 154 | EXPORT_LKL_SYSCALL(mmap) 155 | EXPORT_LKL_SYSCALL(mount) 156 | EXPORT_LKL_SYSCALL(move_pages) 157 | EXPORT_LKL_SYSCALL(mprotect) 158 | EXPORT_LKL_SYSCALL(mq_getsetattr) 159 | EXPORT_LKL_SYSCALL(mq_notify) 160 | EXPORT_LKL_SYSCALL(mq_open) 161 | EXPORT_LKL_SYSCALL(mq_timedreceive) 162 | EXPORT_LKL_SYSCALL(mq_timedsend) 163 | EXPORT_LKL_SYSCALL(mq_unlink) 164 | EXPORT_LKL_SYSCALL(mremap) 165 | EXPORT_LKL_SYSCALL(msgctl) 166 | EXPORT_LKL_SYSCALL(msgget) 167 | EXPORT_LKL_SYSCALL(msgrcv) 168 | EXPORT_LKL_SYSCALL(msgsnd) 169 | EXPORT_LKL_SYSCALL(msync) 170 | EXPORT_LKL_SYSCALL(munlock) 171 | EXPORT_LKL_SYSCALL(munlockall) 172 | EXPORT_LKL_SYSCALL(munmap) 173 | EXPORT_LKL_SYSCALL(nanosleep) 174 | EXPORT_LKL_SYSCALL(newfstatat) 175 | EXPORT_LKL_SYSCALL(nfsservctl) 176 | EXPORT_LKL_SYSCALL(oldwait4) 177 | EXPORT_LKL_SYSCALL(open) 178 | EXPORT_LKL_SYSCALL(openat) 179 | EXPORT_LKL_SYSCALL(pause) 180 | EXPORT_LKL_SYSCALL(perf_event_open) 181 | EXPORT_LKL_SYSCALL(personality) 182 | EXPORT_LKL_SYSCALL(pipe) 183 | EXPORT_LKL_SYSCALL(pipe2) 184 | EXPORT_LKL_SYSCALL(pivot_root) 185 | EXPORT_LKL_SYSCALL(poll) 186 | EXPORT_LKL_SYSCALL(ppoll) 187 | EXPORT_LKL_SYSCALL(prctl) 188 | EXPORT_LKL_SYSCALL(pread64) 189 | EXPORT_LKL_SYSCALL(preadv) 190 | EXPORT_LKL_SYSCALL(preadv2) 191 | EXPORT_LKL_SYSCALL(prlimit64) 192 | EXPORT_LKL_SYSCALL(process_vm_readv) 193 | EXPORT_LKL_SYSCALL(process_vm_writev) 194 | EXPORT_LKL_SYSCALL(pselect6) 195 | EXPORT_LKL_SYSCALL(ptrace) 196 | EXPORT_LKL_SYSCALL(pwrite64) 197 | EXPORT_LKL_SYSCALL(pwritev) 198 | EXPORT_LKL_SYSCALL(pwritev2) 199 | EXPORT_LKL_SYSCALL(quotactl) 200 | EXPORT_LKL_SYSCALL(read) 201 | EXPORT_LKL_SYSCALL(readahead) 202 | EXPORT_LKL_SYSCALL(readlink) 203 | EXPORT_LKL_SYSCALL(readlinkat) 204 | EXPORT_LKL_SYSCALL(readv) 205 | EXPORT_LKL_SYSCALL(reboot) 206 | EXPORT_LKL_SYSCALL(recv) 207 | EXPORT_LKL_SYSCALL(recvfrom) 208 | EXPORT_LKL_SYSCALL(recvmmsg) 209 | EXPORT_LKL_SYSCALL(recvmsg) 210 | EXPORT_LKL_SYSCALL(remap_file_pages) 211 | EXPORT_LKL_SYSCALL(removexattr) 212 | EXPORT_LKL_SYSCALL(rename) 213 | EXPORT_LKL_SYSCALL(renameat) 214 | EXPORT_LKL_SYSCALL(renameat2) 215 | EXPORT_LKL_SYSCALL(request_key) 216 | EXPORT_LKL_SYSCALL(restart_syscall) 217 | EXPORT_LKL_SYSCALL(rmdir) 218 | EXPORT_LKL_SYSCALL(rt_sigaction) 219 | EXPORT_LKL_SYSCALL(rt_sigpending) 220 | EXPORT_LKL_SYSCALL(rt_sigprocmask) 221 | EXPORT_LKL_SYSCALL(rt_sigqueueinfo) 222 | EXPORT_LKL_SYSCALL(rt_sigreturn) 223 | EXPORT_LKL_SYSCALL(rt_sigsuspend) 224 | EXPORT_LKL_SYSCALL(rt_sigtimedwait) 225 | EXPORT_LKL_SYSCALL(rt_tgsigqueueinfo) 226 | EXPORT_LKL_SYSCALL(sched_getaffinity) 227 | EXPORT_LKL_SYSCALL(sched_get_priority_max) 228 | EXPORT_LKL_SYSCALL(sched_get_priority_min) 229 | EXPORT_LKL_SYSCALL(sched_getscheduler) 230 | EXPORT_LKL_SYSCALL(sched_rr_get_interval) 231 | EXPORT_LKL_SYSCALL(sched_setaffinity) 232 | EXPORT_LKL_SYSCALL(sched_yield) 233 | EXPORT_LKL_SYSCALL(seccomp) 234 | EXPORT_LKL_SYSCALL(select) 235 | EXPORT_LKL_SYSCALL(semctl) 236 | EXPORT_LKL_SYSCALL(semget) 237 | EXPORT_LKL_SYSCALL(semop) 238 | EXPORT_LKL_SYSCALL(semtimedop) 239 | EXPORT_LKL_SYSCALL(send) 240 | EXPORT_LKL_SYSCALL(sendfile) 241 | EXPORT_LKL_SYSCALL(sendmmsg) 242 | EXPORT_LKL_SYSCALL(sendmsg) 243 | EXPORT_LKL_SYSCALL(sendto) 244 | EXPORT_LKL_SYSCALL(setdomainname) 245 | EXPORT_LKL_SYSCALL(setfsgid) 246 | EXPORT_LKL_SYSCALL(setfsuid) 247 | EXPORT_LKL_SYSCALL(setgid) 248 | EXPORT_LKL_SYSCALL(setgroups) 249 | EXPORT_LKL_SYSCALL(sethostname) 250 | EXPORT_LKL_SYSCALL(setitimer) 251 | EXPORT_LKL_SYSCALL(set_mempolicy) 252 | EXPORT_LKL_SYSCALL(setns) 253 | EXPORT_LKL_SYSCALL(setpgid) 254 | EXPORT_LKL_SYSCALL(setpriority) 255 | EXPORT_LKL_SYSCALL(setregid) 256 | EXPORT_LKL_SYSCALL(setresgid) 257 | EXPORT_LKL_SYSCALL(setresuid) 258 | EXPORT_LKL_SYSCALL(setreuid) 259 | EXPORT_LKL_SYSCALL(setrlimit) 260 | EXPORT_LKL_SYSCALL(set_robust_list) 261 | EXPORT_LKL_SYSCALL(setsid) 262 | EXPORT_LKL_SYSCALL(setsockopt) 263 | EXPORT_LKL_SYSCALL(set_tid_address) 264 | EXPORT_LKL_SYSCALL(settimeofday) 265 | EXPORT_LKL_SYSCALL(setuid) 266 | EXPORT_LKL_SYSCALL(setxattr) 267 | EXPORT_LKL_SYSCALL(shmat) 268 | EXPORT_LKL_SYSCALL(shmctl) 269 | EXPORT_LKL_SYSCALL(shmdt) 270 | EXPORT_LKL_SYSCALL(shmget) 271 | EXPORT_LKL_SYSCALL(shutdown) 272 | EXPORT_LKL_SYSCALL(sigaltstack) 273 | EXPORT_LKL_SYSCALL(signalfd) 274 | EXPORT_LKL_SYSCALL(signalfd4) 275 | EXPORT_LKL_SYSCALL(socket) 276 | EXPORT_LKL_SYSCALL(socketpair) 277 | EXPORT_LKL_SYSCALL(splice) 278 | EXPORT_LKL_SYSCALL(stat) 279 | EXPORT_LKL_SYSCALL(statfs) 280 | EXPORT_LKL_SYSCALL(swapoff) 281 | EXPORT_LKL_SYSCALL(swapon) 282 | EXPORT_LKL_SYSCALL(symlink) 283 | EXPORT_LKL_SYSCALL(symlinkat) 284 | EXPORT_LKL_SYSCALL(sync) 285 | EXPORT_LKL_SYSCALL(sync_file_range) 286 | EXPORT_LKL_SYSCALL(syncfs) 287 | EXPORT_LKL_SYSCALL(syscalls) 288 | EXPORT_LKL_SYSCALL(_sysctl) 289 | EXPORT_LKL_SYSCALL(sysinfo) 290 | EXPORT_LKL_SYSCALL(syslog) 291 | EXPORT_LKL_SYSCALL(tee) 292 | EXPORT_LKL_SYSCALL(tgkill) 293 | EXPORT_LKL_SYSCALL(time) 294 | EXPORT_LKL_SYSCALL(timer_create) 295 | EXPORT_LKL_SYSCALL(timer_delete) 296 | EXPORT_LKL_SYSCALL(timerfd_create) 297 | EXPORT_LKL_SYSCALL(timerfd_gettime) 298 | EXPORT_LKL_SYSCALL(timerfd_settime) 299 | EXPORT_LKL_SYSCALL(timer_getoverrun) 300 | EXPORT_LKL_SYSCALL(timer_gettime) 301 | EXPORT_LKL_SYSCALL(timer_settime) 302 | EXPORT_LKL_SYSCALL(times) 303 | EXPORT_LKL_SYSCALL(tkill) 304 | EXPORT_LKL_SYSCALL(truncate) 305 | EXPORT_LKL_SYSCALL(umask) 306 | EXPORT_LKL_SYSCALL(umount) 307 | EXPORT_LKL_SYSCALL(umount2) 308 | EXPORT_LKL_SYSCALL(uname) 309 | EXPORT_LKL_SYSCALL(unlink) 310 | EXPORT_LKL_SYSCALL(unlinkat) 311 | EXPORT_LKL_SYSCALL(unshare) 312 | EXPORT_LKL_SYSCALL(uselib) 313 | EXPORT_LKL_SYSCALL(userfaultfd) 314 | EXPORT_LKL_SYSCALL(ustat) 315 | EXPORT_LKL_SYSCALL(utime) 316 | EXPORT_LKL_SYSCALL(utimensat) 317 | EXPORT_LKL_SYSCALL(utimes) 318 | EXPORT_LKL_SYSCALL(vfork) 319 | EXPORT_LKL_SYSCALL(vhangup) 320 | EXPORT_LKL_SYSCALL(vmsplice) 321 | EXPORT_LKL_SYSCALL(wait4) 322 | EXPORT_LKL_SYSCALL(waitid) 323 | EXPORT_LKL_SYSCALL(write) 324 | EXPORT_LKL_SYSCALL(writev) 325 | 326 | EXPORT_HOST_SYSCALL(arch_prctl) 327 | EXPORT_HOST_SYSCALL(iopl) 328 | EXPORT_HOST_SYSCALL(ioperm) 329 | EXPORT_HOST_SYSCALL(getcpu) 330 | 331 | printf("#undef __LKL_SYSCALL\n"); 332 | return 0; 333 | } 334 | --------------------------------------------------------------------------------