Initial revision.
[diskpinger] / diskpinger.c
1 /* emikulic@gmail.com was here 2013 */
2 #define _GNU_SOURCE /* for O_NOATIME and O_DIRECT */
3
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <err.h>
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <stdio.h>
10 #include <unistd.h>
11 #include <stdlib.h>
12 #include <time.h>
13
14 static const char scratch_file_name[] = "scratch";
15 /* also block and fragment size of root fs: */
16 static const size_t buf_size = 4096;
17 /* write at most this often: */
18 static const int period_usec = 500000;
19
20 int main() {
21 int fd;
22 char *buf;
23
24 if (posix_memalign((void**)(&buf), buf_size, buf_size) != 0)
25 errx(1, "posix_memalign() failed");
26
27 if ((fd = open(scratch_file_name,
28 O_CREAT | O_TRUNC | O_NOATIME | O_RDWR | O_DIRECT,
29 0600)) == -1)
30 err(1, "open() failed");
31 /* O_SYNC doesn't seem to be needed here. */
32
33 for (;;) {
34 ssize_t ret;
35 struct timespec t1, t2, tr;
36 int diff_sec, diff_nsec, sleep_len;
37
38 if (clock_gettime(CLOCK_REALTIME, &tr) == -1)
39 err(1, "clock_gettime() failed");
40 if (clock_gettime(CLOCK_MONOTONIC, &t1) == -1)
41 err(1, "clock_gettime() failed");
42
43 ret = pwrite(fd, buf, buf_size, 0);
44 if (ret == -1)
45 err(1, "pwrite() failed (errno=%d)", errno);
46 if (ret != buf_size)
47 warn("pwrite() returned %d, expected %d", (int)ret, (int)buf_size);
48
49 if (clock_gettime(CLOCK_MONOTONIC, &t2) == -1)
50 err(1, "clock_gettime() failed");
51
52 diff_sec = t2.tv_sec - t1.tv_sec;
53 diff_nsec = t2.tv_nsec - t1.tv_nsec;
54 if (diff_nsec < 0) {
55 diff_sec--;
56 diff_nsec += 1000000000;
57 }
58
59 printf("r %d.%09d m %d.%09d wr %d.%09d\n",
60 (int)tr.tv_sec, (int)tr.tv_nsec,
61 (int)t1.tv_sec, (int)t1.tv_nsec,
62 diff_sec, diff_nsec);
63 fflush(stdout);
64
65 if (diff_sec > 0) {
66 sleep_len = 1;
67 } else {
68 sleep_len = period_usec - diff_nsec / 1000;
69 if (sleep_len < 0)
70 sleep_len = 1;
71 }
72 usleep(sleep_len);
73 }
74 return 0;
75 }
76 /* vim:set ts=2 sw=2 et tw=80: */