source: benchmark/io/sendfile/producer.c @ 1a0b600

ADTast-experimentalenumpthread-emulationqualifiedEnum
Last change on this file since 1a0b600 was 1a0b600, checked in by Thierry Delisle <tdelisle@…>, 3 years ago

Implemented producer to use sendfile and splice.

  • Property mode set to 100644
File size: 8.1 KB
Line 
1// programs that sends a file many times as fast as it can
2// compares sendfile to splice
3
4#define _GNU_SOURCE
5
6#include <stdint.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10
11#include <errno.h>
12#include <time.h>
13#include <unistd.h>
14
15#include <sys/ioctl.h>
16#include <sys/sendfile.h>
17#include <sys/socket.h>
18#include <sys/stat.h>
19#include <sys/types.h>
20#include <fcntl.h>
21
22#include <netinet/in.h>
23#include <arpa/inet.h>
24#include <netdb.h>
25
26
27enum {
28        USAGE_ERROR = 1,
29        HOST_ERROR,
30        PIPE_ERROR,
31        FSTAT_ERROR,
32        SOCKET_ERROR,
33        CONNECT_ERROR,
34        SENDFILE_ERROR,
35        SPLICEIN_ERROR,
36        SPLICEOUT_ERROR
37};
38
39enum { buffer_len = 10240 };
40char buffer[buffer_len];
41
42enum { TIMEGRAN = 1000000000LL, TIMES = 100000 };
43
44int pipefd[2];
45
46struct stats {
47        size_t calls;
48        size_t bytes;
49        struct {
50                struct {
51                        size_t cnt;
52                        size_t bytes;
53                } r, w;
54        } shorts;
55};
56static void my_sendfile(int out, int in, size_t size, struct stats *);
57static void my_splice  (int out, int in, size_t size, struct stats *);
58typedef void (*sender_t)(int out, int in, size_t size, struct stats *);
59
60static void run(sender_t sender, struct addrinfo * addr, int infd, size_t size);
61
62int main(int argc, char * argv[]) {
63        const char * file_path;
64        struct addrinfo * addr;
65        int file_fd;
66        switch(argc) {
67        case 3:
68                {
69                        // Open the file
70                        const char * const path = argv[2];
71                        int ret = open(path, 0, O_RDONLY);
72                        if(ret < 0) {
73                                fprintf( stderr, "cannot open file '%s': %s\n\n", path, strerror(errno) );
74                                goto USAGE;
75                        }
76
77                        file_path = path;
78                        file_fd = ret;
79
80
81                        // connect to the address
82                        char * state = 0;
83                        char * str = argv[1];
84                        const char * const host = strtok_r(str, ":", &state);
85                        if(NULL == host) {
86                                fprintf( stderr, "Invalid host:port specification, no host.\n\n" );
87                                goto USAGE;
88                        }
89
90                        const char * const port = strtok_r(NULL, ":", &state);
91                        if(NULL == port) {
92                                fprintf( stderr, "Invalid host:port specification, no port.\n\n" );
93                                goto USAGE;
94                        }
95
96                        printf("looking up '%s:%s'\n", host, port);
97
98                        struct addrinfo hints = {};
99                        struct addrinfo * pResultList = NULL;
100
101                        hints.ai_family = AF_INET;
102                        hints.ai_socktype = SOCK_STREAM;
103                        hints.ai_flags = AI_NUMERICSERV;
104
105                        ret = getaddrinfo(host, port, &hints, &pResultList);
106
107                        switch(ret) {
108                        case 0:
109                                addr = pResultList;
110                                goto DONE;
111
112                        case EAI_ADDRFAMILY:
113                                fprintf( stderr, "The specified network host does not have any network addresses in the requested address family.\n\n" );
114                                break;
115
116                        case EAI_AGAIN:
117                                fprintf( stderr, "The name server returned a temporary failure indication. Try again later.\n\n" );
118                                exit( HOST_ERROR );
119
120                        case EAI_BADFLAGS:
121                                fprintf( stderr, "hints.ai_flags  contains invalid flags; or, hints.ai_flags included AI_CANONNAME and name was NULL.\n\n" );
122                                exit( HOST_ERROR );
123
124                        case EAI_FAIL:
125                                fprintf( stderr, "The name server returned a permanent failure indication.\n\n" );
126                                break;
127
128                        case EAI_FAMILY:
129                                fprintf( stderr, "The requested address family is not supported.\n\n" );
130                                exit( HOST_ERROR );
131
132                        case EAI_MEMORY:
133                                fprintf( stderr, "Out of memory.\n\n" );
134                                exit( HOST_ERROR );
135
136                        case EAI_NODATA:
137                                fprintf( stderr, "The specified network host exists, but does not have any network addresses defined.\n\n" );
138                                break;
139
140                        case EAI_NONAME:
141                                fprintf( stderr, "The unkonwn host or invalid port.\n\n" );
142                                break;
143
144                        case EAI_SERVICE:
145                                fprintf( stderr, "The requested service is not available for the requested socket type.\n\n" );
146                                break;
147
148                        case EAI_SOCKTYPE:
149                                fprintf( stderr, "The requested  socket  type  is  not  supported.\n\n" );
150                                exit( HOST_ERROR );
151
152                        case EAI_SYSTEM:
153                                // Other system error, check errno for details.
154                        default:
155                                fprintf( stderr, "Unnown hostname error: (%d) %s\n\n", (int)errno, strerror(errno) );
156                                exit( HOST_ERROR );
157                        }
158                        if(pResultList) freeaddrinfo(pResultList);
159                        goto USAGE;
160                }
161        USAGE:
162        default:
163                fprintf( stderr, "USAGE: %s host:port file\n", argv[0] );
164                exit( USAGE_ERROR );
165        }
166
167        DONE:
168
169        {
170                char addr_str[INET_ADDRSTRLEN];
171                struct sockaddr_in * address = (struct sockaddr_in *) addr->ai_addr;
172                inet_ntop( AF_INET, &address->sin_addr, addr_str, INET_ADDRSTRLEN );
173                printf("sending '%s' to '%s:%i'\n", file_path, addr_str, ntohs(address->sin_port));
174        }
175
176        int ret = pipe(pipefd);
177        if( ret < 0 ) {
178                fprintf( stderr, "pipe error: (%d) %s\n\n", (int)errno, strerror(errno) );
179                exit( PIPE_ERROR );
180        }
181
182        {
183                ret = fcntl(pipefd[0], F_GETPIPE_SZ);
184                if( ret < 0 ) {
185                        fprintf( stderr, "pipe fcntl error: (%d) %s\n\n", (int)errno, strerror(errno) );
186                        exit( PIPE_ERROR );
187                }
188                printf("%d\n", ret);
189
190                ret = fcntl(pipefd[1], F_GETPIPE_SZ);
191                if( ret < 0 ) {
192                        fprintf( stderr, "pipe fcntl 2 error: (%d) %s\n\n", (int)errno, strerror(errno) );
193                        exit( PIPE_ERROR );
194                }
195                printf("%d\n", ret);
196        }
197
198        size_t file_size = 0;
199        {
200                struct stat buf;
201                ret = fstat(file_fd, &buf);
202                if(0 != ret) {
203                        fprintf( stderr, "fstat error: (%d) %s\n\n", (int)errno, strerror(errno) );
204                        exit( FSTAT_ERROR );
205                }
206                file_size = buf.st_size;
207        }
208
209        printf("--- splice ---\n");
210        run(my_splice  , addr, file_fd, file_size);
211        printf("--- sendfile ---\n");
212        run(my_sendfile, addr, file_fd, file_size);
213
214        close(pipefd[0]);
215        close(pipefd[1]);
216        close(file_fd);
217        return 0;
218}
219
220static void run(sender_t sender, struct addrinfo * addr, int infd, size_t size) {
221
222        int sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
223      if(sock < 0) {
224                fprintf( stderr, "socket error: (%d) %s\n\n", (int)errno, strerror(errno) );
225                exit( SOCKET_ERROR );
226      }
227
228      int ret = connect(sock, addr->ai_addr, addr->ai_addrlen);
229      if(ret < 0) {
230            fprintf( stderr, "connect error: (%d) %s\n\n", (int)errno, strerror(errno) );
231                exit( CONNECT_ERROR );
232      }
233
234        struct stats st;
235        st.calls = 0;
236        st.bytes = 0;
237        st.shorts.r.cnt = 0;
238        st.shorts.r.bytes = 0;
239        st.shorts.w.cnt = 0;
240        st.shorts.w.bytes = 0;
241
242        struct timespec after, before;
243
244        clock_gettime(CLOCK_MONOTONIC, &before);
245
246        for(long long int i = 0; i < TIMES; i++) {
247                sender( sock, infd, size, &st );
248        }
249
250        clock_gettime(CLOCK_MONOTONIC, &after);
251
252        close(sock);
253
254        uint64_t tb = ((int64_t)before.tv_sec * TIMEGRAN) + before.tv_nsec;
255        uint64_t ta = ((int64_t)after.tv_sec * TIMEGRAN) + after.tv_nsec;
256        double secs = ((double)ta - tb) / TIMEGRAN;
257
258        printf("Sent %'zu bytes in %'zu files, %f seconds\n", st.bytes, st.calls, secs);
259        printf(" - %'3.3f bytes per second\n", (((double)st.bytes) / secs));
260        printf(" - %'3.3f bytes per calls\n", (((double)st.bytes) / st.calls));
261        if(st.shorts.r.cnt ){
262                printf(" - %'zu short reads\n", st.shorts.r.cnt);
263                printf(" - %'3.3f bytes per short read\n", (((double)st.shorts.r.bytes) / st.shorts.r.cnt));
264        } else printf("No short reads\n");
265        if(st.shorts.w.cnt ){
266                printf(" - %'zu short reads\n", st.shorts.w.cnt);
267                printf(" - %'3.3f bytes per short read\n", (((double)st.shorts.w.bytes) / st.shorts.w.cnt));
268        } else printf("No short writes\n");
269}
270
271static void my_sendfile(int out, int in, size_t size, struct stats * st) {
272        off_t off = 0;
273        for(;;) {
274
275                ssize_t ret = sendfile(out, in, &off, size);
276                if(ret < 0) {
277                        fprintf( stderr, "connect error: (%d) %s\n\n", (int)errno, strerror(errno) );
278                        exit( SENDFILE_ERROR );
279                }
280
281                st->calls++;
282                st->bytes += ret;
283                off += ret;
284                size -= ret;
285                if( size == 0 ) return;
286                st->shorts.r.cnt++;
287                st->shorts.r.bytes += ret;
288        }
289}
290
291static void my_splice  (int out, int in, size_t size, struct stats * st) {
292        unsigned flags = 0; //SPLICE_F_MOVE; // | SPLICE_F_MORE;
293        off_t offset = 0;
294        size_t writes = 0;
295        for(;;) {
296                ssize_t reti = 0;
297                reti = splice(in, &offset, pipefd[1], NULL, size, flags);
298                if( reti < 0 ) {
299                        fprintf( stderr, "splice in error: (%d) %s\n\n", (int)errno, strerror(errno) );
300                        exit( SPLICEIN_ERROR );
301                }
302
303                size -= reti;
304                size_t in_pipe = reti;
305                for(;;) {
306                        ssize_t reto = 0;
307                        reto = splice(pipefd[0], NULL, out, NULL, in_pipe, flags);
308                        if( reto < 0 ) {
309                                fprintf( stderr, "splice out error: (%d) %s\n\n", (int)errno, strerror(errno) );
310                                exit( SPLICEOUT_ERROR );
311                        }
312                        in_pipe -= reto;
313                        writes += reto;
314                        if(0 == in_pipe) break;
315                        st->shorts.w.cnt++;
316                        st->shorts.w.bytes += reto;
317                }
318                if(0 == size) break;
319                st->shorts.r.cnt++;
320                st->shorts.r.bytes += reti;
321        }
322        st->calls++;
323        st->bytes += writes;
324}
Note: See TracBrowser for help on using the repository browser.