1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/* This program benchmarks a QEMUD pipe to exchange data with a test
18 * server.
19 *
20 * See test_host_1.c for the corresponding server code, which simply
21 * sends back anything it receives from the client.
22 */
23#include <stddef.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <errno.h>
27#include <string.h>
28#include "test_util.h"
29
30#define  PIPE_NAME  "pingpong"
31
32char* progname;
33
34static void usage(int code)
35{
36    printf("Usage: %s [options]\n\n", progname);
37    printf(
38      "Valid options are:\n\n"
39      "  -? -h --help  Print this message\n"
40      "  -pipe <name>  Use pipe name (default: " PIPE_NAME ")\n"
41      "  -tcp <port>   Use local tcp port\n"
42      "  -size <size>  Specify packet size\n"
43      "\n"
44    );
45    exit(code);
46}
47
48int main(int argc, char** argv)
49{
50    Pipe        pipe[1];
51    const char* tcpPort = NULL;
52    int         localPort = 0;
53    const char* pipeName = NULL;
54    const char* packetSize = NULL;
55    int         port = 8012;
56    int         maxCount   = 1000;
57    int         bufferSize = 16384;
58    uint8_t*    buffer;
59    uint8_t*    buffer2;
60    int         nn, count;
61    double      time0, time1;
62
63    /* Extract program name */
64    {
65        char* p = strrchr(argv[0], '/');
66        if (p == NULL)
67            progname = argv[0];
68        else
69            progname = p+1;
70    }
71
72    /* Parse options */
73    while (argc > 1 && argv[1][0] == '-') {
74        char* arg = argv[1];
75        if (!strcmp(arg, "-?") || !strcmp(arg, "-h") || !strcmp(arg, "--help")) {
76            usage(0);
77        } else if (!strcmp(arg, "-pipe")) {
78            if (argc < 3) {
79                fprintf(stderr, "-pipe option needs an argument! See --help for details.\n");
80                exit(1);
81            }
82            argc--;
83            argv++;
84            pipeName = argv[1];
85        } else if (!strcmp(arg, "-tcp")) {
86            if (argc < 3) {
87                fprintf(stderr, "-tcp option needs an argument! See --help for details.\n");
88                exit(1);
89            }
90            argc--;
91            argv++;
92            tcpPort = argv[1];
93        } else if (!strcmp(arg, "-size")) {
94            if (argc < 3) {
95                fprintf(stderr, "-tcp option needs an argument! See --help for details.\n");
96                exit(1);
97            }
98            argc--;
99            argv++;
100            packetSize = argv[1];
101        } else {
102            fprintf(stderr, "UNKNOWN OPTION: %s\n\n", arg);
103            usage(1);
104        }
105        argc--;
106        argv++;
107    }
108
109    /* Check arguments */
110    if (tcpPort && pipeName) {
111        fprintf(stderr, "You can't use both -pipe and -tcp at the same time\n");
112        exit(2);
113    }
114
115    if (tcpPort != NULL) {
116        localPort = atoi(tcpPort);
117        if (localPort <= 0 || localPort > 65535) {
118            fprintf(stderr, "Invalid port number: %s\n", tcpPort);
119            exit(2);
120        }
121    } else if (pipeName == NULL) {
122        /* Use default pipe name */
123        pipeName = PIPE_NAME;
124    }
125
126    if (packetSize != NULL) {
127        int  size = atoi(packetSize);
128        if (size <= 0) {
129            fprintf(stderr, "Invalid byte size: %s\n", packetSize);
130            exit(3);
131        }
132        bufferSize = size;
133    }
134
135    /* Open the pipe */
136    if (tcpPort != NULL) {
137        if (pipe_openSocket(pipe, localPort) < 0) {
138            fprintf(stderr, "Could not open tcp socket!\n");
139            return 1;
140        }
141        printf("Connected to tcp:localhost:%d\n", port);
142    }
143    else {
144        if (pipe_openQemuPipe(pipe, pipeName) < 0) {
145            fprintf(stderr, "Could not open '%s' pipe: %s\n", pipeName, strerror(errno));
146            return 1;
147        }
148        printf("Connected to '%s' pipe\n", pipeName);
149    }
150
151    /* Allocate buffers, setup their data */
152    buffer  = malloc(bufferSize);
153    buffer2 = malloc(bufferSize);
154
155    for (nn = 0; nn < bufferSize; nn++) {
156        buffer[nn] = (uint8_t)nn;
157    }
158
159    /* Do the work! */
160    time0 = now_secs();
161
162    for (count = 0; count < maxCount; count++) {
163        int ret = pipe_send(pipe, buffer, bufferSize);
164        int pos, len;
165
166        if (ret < 0) {
167            fprintf(stderr,"%d: Sending %d bytes failed: %s\n", count, bufferSize, strerror(errno));
168            return 1;
169        }
170
171#if 1
172        /* The server is supposed to send the message back */
173        pos = 0;
174        len = bufferSize;
175        while (len > 0) {
176            ret = pipe_recv(pipe, buffer2 + pos, len);
177            if (ret < 0) {
178                fprintf(stderr, "Receiving failed (ret=%d): %s\n", ret, strerror(errno));
179                return 3;
180            }
181            if (ret == 0) {
182                fprintf(stderr, "Disconnection while receiving!\n");
183                return 4;
184            }
185            pos += ret;
186            len -= ret;
187        }
188
189        if (memcmp(buffer, buffer2, bufferSize) != 0) {
190            fprintf(stderr, "Message content mismatch!\n");
191            const int maxAvail = 16;
192            const int maxLines = 12;
193            int numLines = 0;
194            for (nn = 0; nn < bufferSize; ) {
195                int avail = bufferSize - nn;
196                int mm;
197                if (avail > maxAvail)
198                    avail = maxAvail;
199
200                if (memcmp(buffer+nn, buffer2+nn, avail) != 0) {
201                    if (++numLines >= maxLines) {
202                        printf(".... to be continued ...\n");
203                        break;
204                    }
205                    printf("%04x:", nn);
206
207                    for (mm = 0; mm < avail; mm++)
208                        printf(" %02x", buffer[nn+mm]);
209                    for ( ; mm < maxAvail; mm++ )
210                        printf("   ");
211
212                    printf( " -- " );
213
214                    for (mm = 0; mm < avail; mm++)
215                        printf(" %02x", buffer2[nn+mm]);
216
217                    printf ("\n");
218                }
219                nn += avail;
220            }
221            return 6;
222        }
223
224#endif
225
226        if (count > 0 && (count % 200) == 0) {
227            printf("... %d\n", count);
228        }
229    }
230
231    time1 = now_secs();
232
233    printf("Closing pipe\n");
234    pipe_close(pipe);
235
236    printf("Total time: %g seconds\n", time1 - time0);
237    printf("Total bytes: %g bytes\n", 1.0*maxCount*bufferSize);
238    printf("Bandwidth: %g MB/s\n", (maxCount*bufferSize/(1024.0*1024.0))/(time1 - time0) );
239    return 0;
240}
241