diff options
-rw-r--r-- | LICENSE | 15 | ||||
-rw-r--r-- | measure.c | 74 | ||||
-rw-r--r-- | yes.c | 154 |
3 files changed, 243 insertions, 0 deletions
@@ -0,0 +1,15 @@ +ISC License + +© 2017 Mattias Andrée <maandree@kth.se> + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/measure.c b/measure.c new file mode 100644 index 0000000..ef06c5b --- /dev/null +++ b/measure.c @@ -0,0 +1,74 @@ +/* See LICENSE file for copyright and license details. */ + +#define _GNU_SOURCE +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + + +#ifndef CAPACITY +# define CAPACITY (1 << 20) +#endif + + +int +main(int argc, char *argv[]) +{ + int fd, n = 0, m = 150000; + ssize_t r; + size_t sum = 0, totsum = 0; + struct timespec start, end; + double rate; + + if (!argc) + *argv = "measure"; + + if (argc > 1) + m = atoi(argv[1]); + + fd = open("/dev/null", O_WRONLY); + if (fd < 0) + goto fail; + + usleep(10000L); + if (argc < 2 && fcntl(STDIN_FILENO, F_GETPIPE_SZ) == CAPACITY) + m = 10; + + if (clock_gettime(CLOCK_MONOTONIC, &start)) + goto fail; + for (;;) { + r = splice(STDIN_FILENO, NULL, fd, NULL, SSIZE_MAX, 0); + if (r <= 0) { + if (r < 0) + goto fail; + goto done; + } + sum += (size_t)r; + if (++n == m) { + if (clock_gettime(CLOCK_MONOTONIC, &end)) + goto fail; + n = 0; + start.tv_sec = end.tv_sec - start.tv_sec; + start.tv_nsec = end.tv_nsec - start.tv_nsec; + rate = (double)start.tv_nsec; + rate /= 1000000000.; + rate += start.tv_sec; + rate = (double)sum / rate; + rate /= 1000000000.; + totsum += sum; + sum = 0; + dprintf(STDERR_FILENO, " %lf GB/s\033[K\n\033[A", rate); + start = end; + } + } + +done: + return 0; + +fail: + perror(*argv); + return 1; +} @@ -0,0 +1,154 @@ +/* See LICENSE file for copyright and license details. */ + +#define _GNU_SOURCE +#include <sys/ioctl.h> +#include <sys/uio.h> +#include <alloca.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +#ifndef CAPACITY +# define CAPACITY (1 << 20) +#endif + + +static char *argv0; +static void (*writeall)(char *, size_t); + + +static void +writeall_write(char *buf, size_t n) +{ + ssize_t r; + for (; n; n -= (size_t)r, buf += r) + if ((r = write(STDOUT_FILENO, buf, n)) < 0) + perror(argv0), exit(1); +} + +#if 0 +static void +writeall_vmsplice(char *buf, size_t n) +{ + struct iovec iov; + ssize_t r; + iov.iov_base = buf; + iov.iov_len = n; + while (iov.iov_len) { + r = vmsplice(STDOUT_FILENO, &iov, 1, 0); + if (r < 0) { + if (errno == EINVAL) { + writeall = writeall_write; + writeall_write(iov.iov_base, iov.iov_len); + return; + } + perror(argv0), exit(1); + } + iov.iov_base += r; + iov.iov_len -= (size_t)r; + } +} +#endif + +int +main(int argc, char *argv[]) +{ + size_t n, len, m = 0, p, cap = 0; + char *buf, *b; + int i, sz, fds[2], flags; + ssize_t r; + + if (!argc) + argc = 1; + argv0 = argv[0] ? argv[0] : "yes"; + if (argc == 1) { + argc = 2; + argv = (char *[]){argv0, "y"}; + } + n = (size_t)(argc - 1); + + writeall = writeall_write; + + for (i = 1; i < argc; i++) + n += strlen(argv[i]); + b = buf = alloca(n); + for (i = 1; i < argc; i++) { + b = stpcpy(b, argv[i]); + *b++ = ' '; + } + b[-1] = '\n'; + + if (pipe(fds)) + goto fail; + + if (fds[0] == STDOUT_FILENO || fds[1] == STDOUT_FILENO) { + errno = EBADF; + goto fail; + } + + if ((flags = fcntl(fds[1], F_GETFL)) == -1) + goto fail; + if (fcntl(fds[1], F_SETFL, flags | O_NONBLOCK) == -1) + goto fail; + + if ((sz = fcntl(STDOUT_FILENO, F_GETPIPE_SZ)) > 0) { + if (sz < CAPACITY) + if (fcntl(STDOUT_FILENO, F_SETPIPE_SZ, CAPACITY) != -1) + sz = CAPACITY; + fcntl(fds[1], F_SETPIPE_SZ, sz); + } else { + fcntl(fds[1], F_SETPIPE_SZ, 3 << 16); + } + + for (b = buf, p = n;;) { + r = write(fds[1], b, p); + if (r < 0) { + if (errno == EAGAIN) + break; + goto fail; + } + b += r; + cap += (size_t)r; + p -= (size_t)r; + if (!p) { + b = buf; + p = n; + m += 1; + } + } + + cap -= cap % n; + len = n; + n *= m; + if (m) + cap = n; + + for (;;) { + r = tee(fds[0], STDOUT_FILENO, cap, 0); + if (r < (ssize_t)n) { + if (r < 0) { + if (errno == EINVAL) + goto fallback; + goto fail; + } + r %= len; + writeall(buf + r, len - r); + } + } + +fallback: + for (p = 0;; p = (p + (size_t)r) % len) { + if ((r = write(STDOUT_FILENO, buf + p, len - p)) < 0) + goto fail; + } + + return 0; + +fail: + perror(argv0); + return 1; +} |