eglGetFrameTimestamps: Allow reads done to equal rendering complete.
[platform/upstream/VK-GL-CTS.git] / execserver / tools / xsClient.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Execution Server
3  * ---------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief ExecServer Client.
22  *//*--------------------------------------------------------------------*/
23
24 #include "xsDefs.hpp"
25 #include "xsProtocol.hpp"
26 #include "deSocket.hpp"
27 #include "deUniquePtr.hpp"
28
29 #include "deString.h"
30
31 #include <memory>
32 #include <sstream>
33 #include <fstream>
34 #include <cstdio>
35 #include <cstdlib>
36
37 using std::string;
38 using std::vector;
39
40 namespace xs
41 {
42
43 typedef de::UniquePtr<Message> ScopedMsgPtr;
44
45 class SocketError : public Error
46 {
47 public:
48         SocketError (deSocketResult result, const char* message, const char* file, int line)
49                 : Error         (message, deGetSocketResultName(result), file, line)
50                 , m_result      (result)
51         {
52         }
53
54         deSocketResult getResult (void) const
55         {
56                 return m_result;
57         }
58
59 private:
60         deSocketResult m_result;
61 };
62
63 // Helpers.
64 void sendMessage (de::Socket& socket, const Message& message)
65 {
66         // Format message.
67         vector<deUint8> buf;
68         message.write(buf);
69
70         // Write to socket.
71         size_t pos = 0;
72         while (pos < buf.size())
73         {
74                 size_t                  numLeft         = buf.size() - pos;
75                 size_t                  numSent         = 0;
76                 deSocketResult  result          = socket.send(&buf[pos], numLeft, &numSent);
77
78                 if (result != DE_SOCKETRESULT_SUCCESS)
79                         throw SocketError(result, "send() failed", __FILE__, __LINE__);
80
81                 pos += numSent;
82         }
83 }
84
85 void readBytes (de::Socket& socket, vector<deUint8>& dst, size_t numBytes)
86 {
87         size_t numRead = 0;
88         dst.resize(numBytes);
89         while (numRead < numBytes)
90         {
91                 size_t                  numLeft         = numBytes - numRead;
92                 size_t                  curNumRead      = 0;
93                 deSocketResult  result          = socket.receive(&dst[numRead], numLeft, &curNumRead);
94
95                 if (result != DE_SOCKETRESULT_SUCCESS)
96                         throw SocketError(result, "receive() failed", __FILE__, __LINE__);
97
98                 numRead += curNumRead;
99         }
100 }
101
102 Message* readMessage (de::Socket& socket)
103 {
104         // Header.
105         vector<deUint8> header;
106         readBytes(socket, header, MESSAGE_HEADER_SIZE);
107
108         MessageType     type;
109         size_t          messageSize;
110         Message::parseHeader(&header[0], (int)header.size(), type, messageSize);
111
112         // Simple messages without any data.
113         switch (type)
114         {
115                 case MESSAGETYPE_KEEPALIVE:                             return new KeepAliveMessage();
116                 case MESSAGETYPE_PROCESS_STARTED:               return new ProcessStartedMessage();
117                 default:
118                         break; // Read message with data.
119         }
120
121         vector<deUint8> messageBuf;
122         readBytes(socket, messageBuf, messageSize-MESSAGE_HEADER_SIZE);
123
124         switch (type)
125         {
126                 case MESSAGETYPE_HELLO:                                 return new HelloMessage(&messageBuf[0], (int)messageBuf.size());
127                 case MESSAGETYPE_TEST:                                  return new TestMessage(&messageBuf[0], (int)messageBuf.size());
128                 case MESSAGETYPE_PROCESS_LOG_DATA:              return new ProcessLogDataMessage(&messageBuf[0], (int)messageBuf.size());
129                 case MESSAGETYPE_INFO:                                  return new InfoMessage(&messageBuf[0], (int)messageBuf.size());
130                 case MESSAGETYPE_PROCESS_LAUNCH_FAILED: return new ProcessLaunchFailedMessage(&messageBuf[0], (int)messageBuf.size());
131                 case MESSAGETYPE_PROCESS_FINISHED:              return new ProcessFinishedMessage(&messageBuf[0], (int)messageBuf.size());
132                 default:
133                         XS_FAIL("Unknown message");
134         }
135 }
136
137 class CommandLine
138 {
139 public:
140         de::SocketAddress       address;
141         std::string                     program;
142         std::string                     params;
143         std::string                     workingDir;
144         std::string                     caseList;
145         std::string                     dstFileName;
146 };
147
148 class Client
149 {
150 public:
151                                                 Client          (const CommandLine& cmdLine);
152                                                 ~Client         (void);
153
154         void                            run                     (void);
155
156 private:
157         const CommandLine&      m_cmdLine;
158         de::Socket                      m_socket;
159 };
160
161 Client::Client (const CommandLine& cmdLine)
162         : m_cmdLine(cmdLine)
163 {
164 }
165
166 Client::~Client (void)
167 {
168 }
169
170 void Client::run (void)
171 {
172         // Connect to server.
173         m_socket.connect(m_cmdLine.address);
174
175         printf("Connected to %s:%d!\n", m_cmdLine.address.getHost(), m_cmdLine.address.getPort());
176
177         // Open result file.
178         std::fstream out(m_cmdLine.dstFileName.c_str(), std::fstream::out|std::fstream::binary);
179
180         printf("  writing to %s\n", m_cmdLine.dstFileName.c_str());
181
182         // Send execution request.
183         {
184                 ExecuteBinaryMessage msg;
185
186                 msg.name                = m_cmdLine.program;
187                 msg.params              = m_cmdLine.params;
188                 msg.workDir             = m_cmdLine.workingDir;
189                 msg.caseList    = m_cmdLine.caseList;
190
191                 sendMessage(m_socket, msg);
192                 printf("  execution request sent.\n");
193         }
194
195         // Run client loop.
196         bool isRunning = true;
197         while (isRunning)
198         {
199                 ScopedMsgPtr msg(readMessage(m_socket));
200
201                 switch (msg->type)
202                 {
203                         case MESSAGETYPE_HELLO:
204                                 printf("  HelloMessage\n");
205                                 break;
206
207                         case MESSAGETYPE_KEEPALIVE:
208                         {
209                                 printf("  KeepAliveMessage\n");
210
211                                 // Reply with keepalive.
212                                 sendMessage(m_socket, KeepAliveMessage());
213                                 break;
214                         }
215
216                         case MESSAGETYPE_INFO:
217                                 printf("  InfoMessage: '%s'\n", static_cast<InfoMessage*>(msg.get())->info.c_str());
218                                 break;
219
220                         case MESSAGETYPE_PROCESS_STARTED:
221                                 printf("  ProcessStartedMessage\n");
222                                 break;
223
224                         case MESSAGETYPE_PROCESS_FINISHED:
225                                 printf("  ProcessFinished: exit code = %d\n", static_cast<ProcessFinishedMessage*>(msg.get())->exitCode);
226                                 isRunning = false;
227                                 break;
228
229                         case MESSAGETYPE_PROCESS_LAUNCH_FAILED:
230                                 printf("  ProcessLaunchFailed: '%s'\n", static_cast<ProcessLaunchFailedMessage*>(msg.get())->reason.c_str());
231                                 isRunning = false;
232                                 break;
233
234                         case MESSAGETYPE_PROCESS_LOG_DATA:
235                         {
236                                 ProcessLogDataMessage* logDataMsg = static_cast<ProcessLogDataMessage*>(msg.get());
237                                 printf("  ProcessLogDataMessage: %d bytes\n", (int)logDataMsg->logData.length());
238                                 out << logDataMsg->logData;
239                                 break;
240                         }
241
242                         default:
243                                 XS_FAIL("Unknown message");
244                                 break;
245                 }
246         }
247
248         // Close output file.
249         out.close();
250
251         // Close connection.
252         m_socket.shutdown();
253         m_socket.close();
254
255         printf("Done!\n");
256 }
257
258 string parseString (const char* str)
259 {
260         if (str[0] == '\'' || str[0] == '"')
261         {
262                 const char*                     p               = str;
263                 char                            endChar = *p++;
264                 std::ostringstream      o;
265
266                 while (*p != endChar && *p)
267                 {
268                         if (*p == '\\')
269                         {
270                                 switch (p[1])
271                                 {
272                                         case 0:         DE_ASSERT(DE_FALSE);    break;
273                                         case 'n':       o << '\n';                              break;
274                                         case 't':       o << '\t';                              break;
275                                         default:        o << p[1];                              break;
276                                 }
277
278                                 p += 2;
279                         }
280                         else
281                                 o << *p++;
282                 }
283
284                 return o.str();
285         }
286         else
287                 return string(str);
288 }
289
290 void printHelp (const char* binName)
291 {
292         printf("%s:\n", binName);
293         printf("  --host=[host]          Connect to host [host]\n");
294         printf("  --port=[name]          Use port [port]\n");
295         printf("  --program=[program]    Test program\n");
296         printf("  --params=[params]      Test program params\n");
297         printf("  --workdir=[dir]        Working directory\n");
298         printf("  --caselist=[caselist]  Test case list\n");
299         printf("  --out=filename         Test result file\n");
300 }
301
302 int runClient (int argc, const char* const* argv)
303 {
304         CommandLine cmdLine;
305
306         // Defaults.
307         cmdLine.address.setHost("127.0.0.1");
308         cmdLine.address.setPort(50016);
309         cmdLine.dstFileName = "TestResults.qpa";
310
311         // Parse command line.
312         for (int argNdx = 1; argNdx < argc; argNdx++)
313         {
314                 const char* arg = argv[argNdx];
315
316                 if (deStringBeginsWith(arg, "--port="))
317                         cmdLine.address.setPort(atoi(arg+7));
318                 else if (deStringBeginsWith(arg, "--host="))
319                         cmdLine.address.setHost(parseString(arg+7).c_str());
320                 else if (deStringBeginsWith(arg, "--program="))
321                         cmdLine.program = parseString(arg+10);
322                 else if (deStringBeginsWith(arg, "--params="))
323                         cmdLine.params = parseString(arg+9);
324                 else if (deStringBeginsWith(arg, "--workdir="))
325                         cmdLine.workingDir = parseString(arg+10);
326                 else if (deStringBeginsWith(arg, "--caselist="))
327                         cmdLine.caseList = parseString(arg+11);
328                 else if  (deStringBeginsWith(arg, "--out="))
329                         cmdLine.dstFileName = parseString(arg+6);
330                 else
331                 {
332                         printHelp(argv[0]);
333                         return -1;
334                 }
335         }
336
337         // Run client.
338         try
339         {
340                 Client client(cmdLine);
341                 client.run();
342         }
343         catch (const std::exception& e)
344         {
345                 printf("%s\n", e.what());
346                 return -1;
347         }
348
349         return 0;
350 }
351
352 } // xs
353
354 int main (int argc, const char* const* argv)
355 {
356         return xs::runClient(argc, argv);
357 }