aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--LICENSE15
-rw-r--r--measure.c74
-rw-r--r--yes.c154
3 files changed, 243 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..2553a69
--- /dev/null
+++ b/LICENSE
@@ -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;
+}
diff --git a/yes.c b/yes.c
new file mode 100644
index 0000000..2da0ec5
--- /dev/null
+++ b/yes.c
@@ -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;
+}