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