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 
32 char* progname;
33 
usage(int code)34 static 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 
main(int argc,char ** argv)48 int 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