]> git.meshlink.io Git - meshlink/blob - test/stream.c
Add a metering test.
[meshlink] / test / stream.c
1 #define _GNU_SOURCE
2 #define _POSIX_C_SOURCE 200809L
3
4 #include <stdio.h>
5 #include <stdbool.h>
6 #include <stdlib.h>
7 #include <stdint.h>
8 #include <string.h>
9 #include <getopt.h>
10 #include <err.h>
11 #include <time.h>
12 #include <unistd.h>
13
14 int main(int argc, char *argv[]) {
15         static const struct option longopts[] = {
16                 {"verify", 0, NULL, 'v'},
17                 {"rate", 1, NULL, 'r'},
18                 {"fps", 1, NULL, 'f'},
19                 {"total", 1, NULL, 't'},
20                 {NULL, 0, NULL, 0},
21         };
22
23         int opt;
24         bool verify = false;
25         float rate = 1e6;
26         float fps = 60;
27         float total = 1.0 / 0.0;
28
29         while((opt = getopt_long(argc, argv, "vr:f:t:", longopts, &optind)) != -1) {
30                 switch(opt) {
31                 case 'v':
32                         verify = true;
33                         break;
34
35                 case 'r':
36                         rate = atof(optarg);
37                         break;
38
39                 case 'f':
40                         fps = atof(optarg);
41                         break;
42
43                 case 't':
44                         total = atof(optarg);
45                         break;
46
47                 default:
48                         fprintf(stderr, "Usage: %s [-v] [-r bitrate] [-f frames_per_second]\n", argv[0]);
49                         return 1;
50                 }
51         }
52
53         size_t framesize = rate / fps / 8;
54         framesize &= ~0xf;
55         long interval = 1e9 / fps;
56
57         if(!framesize || interval <= 0) {
58                 err(1, "invalid parameters");
59         }
60
61         char *buf = malloc(framesize + 16);
62
63         if(!buf) {
64                 err(1, "malloc(%zu)", framesize);
65         }
66
67         uint64_t counter = 0;
68         struct timespec now, next = {0};
69         clock_gettime(CLOCK_REALTIME, &now);
70
71         while(total > 0) {
72                 if(!verify) {
73                         size_t tosend = framesize;
74                         char *p = buf;
75
76                         memcpy(buf, &now, sizeof(now));
77                         clock_gettime(CLOCK_REALTIME, &now);
78
79                         for(uint64_t *q = (uint64_t *)(buf + sizeof(now)); (char *)q < buf + framesize; q++) {
80                                 *q = counter++;
81                         }
82
83                         while(tosend) {
84                                 ssize_t sent = write(1, p, tosend);
85
86                                 if(sent <= 0) {
87                                         err(1, "write(1, %p, %zu)", (void *)p, tosend);
88                                 }
89
90                                 tosend -= sent;
91                                 p += sent;
92                         }
93
94                         next.tv_sec = 0;
95                         next.tv_nsec = interval;
96
97                         while(next.tv_nsec >= 1000000000) {
98                                 next.tv_nsec -= 1000000000;
99                                 next.tv_sec++;
100                         }
101
102                         nanosleep(&next, NULL);
103                         total -= framesize;
104                 } else {
105                         struct timespec *ts = (struct timespec *)buf;
106                         size_t toread = sizeof(*ts);
107                         char *p = buf;
108
109                         while(toread) {
110                                 ssize_t result = read(0, p, toread);
111
112                                 if(result <= 0) {
113                                         err(1, "read(1, %p, %zu)", (void *)p, toread);
114                                 }
115
116                                 toread -= result;
117                                 p += result;
118                         }
119
120                         clock_gettime(CLOCK_REALTIME, &now);
121
122                         toread = framesize - sizeof(now);
123
124                         while(toread) {
125                                 ssize_t result = read(0, p, toread);
126
127                                 if(result <= 0) {
128                                         err(1, "read(1, %p, %zu)", (void *)p, toread);
129                                 }
130
131                                 toread -= result;
132                                 p += result;
133                         }
134
135                         clock_gettime(CLOCK_REALTIME, &next);
136
137                         for(uint64_t *q = (uint64_t *)(buf + sizeof(now)); (char *)q < buf + framesize; q++) {
138                                 if(*q != counter++) {
139                                         uint64_t offset = (counter - 1) * 8;
140                                         offset += ((counter * 8) / (framesize - sizeof(now))) * sizeof(now);
141                                         err(1, "verification failed at offset %lu", (unsigned long)offset);
142                                 }
143                         }
144
145                         float dt1 = now.tv_sec - ts->tv_sec + 1e-9 * (now.tv_nsec - ts->tv_nsec);
146                         float dt2 = next.tv_sec - now.tv_sec + 1e-9 * (next.tv_nsec - now.tv_nsec);
147
148                         fprintf(stderr, "\rDelay: %8.3f ms, burst bandwidth: %8.0f Mbit/s", dt1 * 1e3, (framesize - sizeof(now)) / dt2 * 8 / 1e6);
149
150                         total -= framesize;
151                 }
152         }
153
154         if(verify) {
155                 fprintf(stderr, "\n");
156         }
157 }