aboutsummaryrefslogtreecommitdiffstats
path: root/limit.c
blob: e7a2cb7af6f76fd7536c3eb28185c9035d622be7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/* See LICENSE file for copyright and license details. */
#include <errno.h>
#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, const char *argv[])
{
	static char buf[1 << 16];
	int rw1[2], rw2[2], n = 0;
	ssize_t r, p, w;
	size_t sum = 0, totsum = 0;
	struct timespec start, end;
	double rate;
	int capacity, flags;

	if (!argc)
		*argv = "limit";

	dprintf(STDERR_FILENO, "Requested capacity: %i\n", CAPACITY);
	if (pipe(rw1) || pipe(rw2))
		goto fail;
	capacity = fcntl(*rw1, F_SETPIPE_SZ, CAPACITY);
	if (capacity < 0 || fcntl(*rw2, F_SETPIPE_SZ, capacity) != capacity)
		goto fail;
	dprintf(STDERR_FILENO, "Configured capacity: %i\n", capacity);

	flags = fcntl(rw1[1], F_GETFL);
	if (flags < 0 || fcntl(rw1[1], F_SETFL, flags |= O_NONBLOCK) < 0)
		goto fail;
	for (n = capacity, capacity = 0; n; n -= (int)r, capacity += (int)r) {
		if ((r = write(rw1[1], buf, (size_t)n)) < 0) {
			if (errno != EAGAIN)
				goto fail;
			n -= 1;
			r = 0;
		}
	}
	dprintf(STDERR_FILENO, "Supported capacity: %i\n", capacity);
	if (fcntl(rw1[1], F_SETFL, flags ^= O_NONBLOCK) < 0)
		goto fail;

	if (clock_gettime(CLOCK_MONOTONIC, &start))
		goto fail;
	for (;;) {
		r = splice(rw1[0], NULL, rw2[1], NULL, (size_t)capacity, 0);
		if (r <= 0) {
			if (r < 0)
				goto fail;
			goto done;
		}
		for (p = 0; p < r; p += w) {
			w = splice(rw2[0], NULL, rw1[1], NULL, (size_t)(r - p), 0);
			if (w <= 0) {
				if (w < 0)
					goto fail;
				goto done;
			}
		}
		sum += (size_t)r << 1;
		if (++n == 100000) {
			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 /= (double)1000000000.f;
			rate += (double)start.tv_sec;
			rate = (double)sum / rate;
			rate /= (double)1000000000.f;
			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;
}