From af519fd928ba2cf920308f8e8c000beeeb35f6e9 Mon Sep 17 00:00:00 2001 From: rwatson Date: Thu, 30 Sep 2004 05:25:00 +0000 Subject: Add syscall_timing, a simple timing micro-benchmark for some characteristic system calls. I've been sending this to people for a while, and figured it would be more efficient to just put it in CVS. --- tools/tools/syscall_timing/Makefile | 9 ++ tools/tools/syscall_timing/syscall_timing.c | 186 ++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 tools/tools/syscall_timing/Makefile create mode 100644 tools/tools/syscall_timing/syscall_timing.c (limited to 'tools') diff --git a/tools/tools/syscall_timing/Makefile b/tools/tools/syscall_timing/Makefile new file mode 100644 index 0000000..0ebdb0e --- /dev/null +++ b/tools/tools/syscall_timing/Makefile @@ -0,0 +1,9 @@ +# +# $FreeBSD$ +# + +PROG= syscall_timing +CFLAGS+= -static -O +NOMAN= yes + +.include diff --git a/tools/tools/syscall_timing/syscall_timing.c b/tools/tools/syscall_timing/syscall_timing.c new file mode 100644 index 0000000..5e44a94 --- /dev/null +++ b/tools/tools/syscall_timing/syscall_timing.c @@ -0,0 +1,186 @@ +/*- + * Copyright (c) 2003-2004 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#define timespecsub(vvp, uvp) \ + do { \ + (vvp)->tv_sec -= (uvp)->tv_sec; \ + (vvp)->tv_nsec -= (uvp)->tv_nsec; \ + if ((vvp)->tv_nsec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_nsec += 1000000000; \ + } \ + } while (0) + +inline void +test_getuid(int num) +{ + int i; + + /* + * Thread-local data should require no locking if system + * call is MPSAFE. + */ + for (i = 0; i < num; i++) + getuid(); +} + +inline void +test_getppid(int num) +{ + int i; + + /* + * This is process-local, but can change, so will require a + * lock. + */ + for (i = 0; i < num; i++) + getppid(); +} + +inline void +test_clock_gettime(int num) +{ + struct timespec ts; + int i; + + for (i = 0; i < num; i++) { + if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { + perror("clock_gettime"); + exit(-1); + } + } +} + +inline void +test_pipe(int num) +{ + int i; + + /* + * pipe creation is expensive, as it will allocate a new file + * descriptor, allocate a new pipe, hook it all up, and return. + * Destroying is also expensive, as we now have to free up + * the file descriptors and return the pipe. + */ + for (i = 0; i < num; i++) { + int fd[2]; + if (pipe(fd) == -1) { + perror("pipe"); + exit(-1); + } + + close(fd[0]); + close(fd[1]); + } +} + +inline void +test_socket(int num) +{ + int i, so; + + /* + * Sockets are also expensive, but unlike pipes, currently + * require Giant. + */ + for (i = 0; i < num; i++) { + so = socket(PF_LOCAL, SOCK_STREAM, 0); + if (so == -1) { + perror("socket"); + exit(-1); + } + close(so); + } +} + +int +main(int argc, char *argv[]) +{ + struct timespec ts_start, ts_end, ts_res; + int count; + + if (argc != 3) { + fprintf(stderr, "syscall_timing [iterations] [test]\n"); + exit(-1); + } + count = atoi(argv[1]); + + assert(clock_getres(CLOCK_REALTIME, &ts_res) == 0); + printf("Clock resolution: %d.%09lu\n", ts_res.tv_sec, ts_res.tv_nsec); + + if (strcmp(argv[2], "getuid") == 0) { + assert(clock_gettime(CLOCK_REALTIME, &ts_start) == 0); + test_getuid(count); + assert(clock_gettime(CLOCK_REALTIME, &ts_end) == 0); + } else if (strcmp(argv[2], "getppid") == 0) { + assert(clock_gettime(CLOCK_REALTIME, &ts_start) == 0); + test_getppid(count); + assert(clock_gettime(CLOCK_REALTIME, &ts_end) == 0); + } else if (strcmp(argv[2], "clock_gettime") == 0) { + assert(clock_gettime(CLOCK_REALTIME, &ts_start) == 0); + test_clock_gettime(count); + assert(clock_gettime(CLOCK_REALTIME, &ts_end) == 0); + } else if (strcmp(argv[2], "pipe") == 0) { + assert(clock_gettime(CLOCK_REALTIME, &ts_start) == 0); + test_pipe(count); + assert(clock_gettime(CLOCK_REALTIME, &ts_end) == 0); + } else if (strcmp(argv[2], "socket") == 0) { + assert(clock_gettime(CLOCK_REALTIME, &ts_start) == 0); + test_socket(count); + assert(clock_gettime(CLOCK_REALTIME, &ts_end) == 0); + } else { + fprintf(stderr, "syscal [iterations] [test]\n"); + exit(-1); + } + + timespecsub(&ts_end, &ts_start); + + printf("%d.%09lu for %d iterations\n", ts_end.tv_sec, + ts_end.tv_nsec, count); + + /* + * Note. This assumes that each iteration takes less than + * a second, and that our total nanoseconds doesn't exceed + * the room in our arithmetic unit. Fine for system calls, + * but not for long things. + */ + ts_end.tv_sec *= 1000000000 / count; + printf("0.%09lu per/iteration\n", + ts_end.tv_sec + ts_end.tv_nsec / count); + return (0); +} -- cgit v1.1