blob: 056848aec16892adeb293dc0a05f0dc07b10a084 [file] [log] [blame]
Pierre Ossmane1f25452015-02-04 14:12:04 +01001/* Copyright 2015 Pierre Ossman <ossman@cendio.se> for Cendio AB
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19/*
20 * This program reads files produced by TightVNC's/TurboVNC's
21 * compare-encodings. It is basically a dump of the RFB protocol
22 * from the server side from the ServerInit message and forward.
23 * It is assumed that the client is using a bgr888 (LE) pixel
24 * format.
25 */
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <math.h>
Pierre Ossman98d7af92015-11-16 09:37:46 +010030#include <sys/time.h>
Pierre Ossmane1f25452015-02-04 14:12:04 +010031
32#include <rdr/Exception.h>
33#include <rdr/FileInStream.h>
34
35#include <rfb/CConnection.h>
36#include <rfb/CMsgReader.h>
Pierre Ossmane1f25452015-02-04 14:12:04 +010037#include <rfb/PixelBuffer.h>
38#include <rfb/PixelFormat.h>
39
40#include "util.h"
41
42// FIXME: Files are always in this format
43static const rfb::PixelFormat filePF(32, 24, false, true, 255, 255, 255, 0, 8, 16);
44
45class CConn : public rfb::CConnection {
46public:
47 CConn(const char *filename);
48 ~CConn();
49
50 virtual void setDesktopSize(int w, int h);
51 virtual void setPixelFormat(const rfb::PixelFormat& pf);
Pierre Ossman6a1a0d02017-02-19 15:48:17 +010052 virtual void setCursor(int, int, const rfb::Point&, const rdr::U8*);
Pierre Ossman9f273e92015-11-09 16:34:54 +010053 virtual void framebufferUpdateStart();
54 virtual void framebufferUpdateEnd();
Pierre Ossmane1f25452015-02-04 14:12:04 +010055 virtual void setColourMapEntries(int, int, rdr::U16*);
56 virtual void bell();
57 virtual void serverCutText(const char*, rdr::U32);
58
59public:
60 double cpuTime;
61
62protected:
63 rdr::FileInStream *in;
Pierre Ossmane1f25452015-02-04 14:12:04 +010064};
65
66CConn::CConn(const char *filename)
67{
Pierre Ossmane1f25452015-02-04 14:12:04 +010068 cpuTime = 0.0;
69
70 in = new rdr::FileInStream(filename);
71 setStreams(in, NULL);
72
Pierre Ossmane1f25452015-02-04 14:12:04 +010073 // Need to skip the initial handshake
74 setState(RFBSTATE_INITIALISATION);
75 // That also means that the reader and writer weren't setup
76 setReader(new rfb::CMsgReader(this, in));
77}
78
79CConn::~CConn()
80{
Pierre Ossmane1f25452015-02-04 14:12:04 +010081 delete in;
Pierre Ossmane1f25452015-02-04 14:12:04 +010082}
83
84void CConn::setDesktopSize(int w, int h)
85{
86 CConnection::setDesktopSize(w, h);
87
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +020088 setFramebuffer(new rfb::ManagedPixelBuffer(filePF,
89 server.width(),
90 server.height()));
Pierre Ossmane1f25452015-02-04 14:12:04 +010091}
92
93void CConn::setPixelFormat(const rfb::PixelFormat& pf)
94{
95 // Override format
96 CConnection::setPixelFormat(filePF);
Pierre Ossmane1f25452015-02-04 14:12:04 +010097}
98
Pierre Ossman6a1a0d02017-02-19 15:48:17 +010099void CConn::setCursor(int, int, const rfb::Point&, const rdr::U8*)
Pierre Ossmane1f25452015-02-04 14:12:04 +0100100{
101}
102
Pierre Ossman9f273e92015-11-09 16:34:54 +0100103void CConn::framebufferUpdateStart()
Pierre Ossmane1f25452015-02-04 14:12:04 +0100104{
Pierre Ossman3da238d2015-11-12 12:20:05 +0100105 CConnection::framebufferUpdateStart();
106
Pierre Ossmane1f25452015-02-04 14:12:04 +0100107 startCpuCounter();
Pierre Ossman9f273e92015-11-09 16:34:54 +0100108}
109
110void CConn::framebufferUpdateEnd()
111{
Pierre Ossman3da238d2015-11-12 12:20:05 +0100112 CConnection::framebufferUpdateEnd();
113
Pierre Ossmane1f25452015-02-04 14:12:04 +0100114 endCpuCounter();
115
116 cpuTime += getCpuCounter();
117}
118
119void CConn::setColourMapEntries(int, int, rdr::U16*)
120{
121}
122
123void CConn::bell()
124{
125}
126
127void CConn::serverCutText(const char*, rdr::U32)
128{
129}
130
Pierre Ossman98d7af92015-11-16 09:37:46 +0100131struct stats
132{
133 double decodeTime;
134 double realTime;
135};
136
137static struct stats runTest(const char *fn)
Pierre Ossmane1f25452015-02-04 14:12:04 +0100138{
139 CConn *cc;
Pierre Ossman98d7af92015-11-16 09:37:46 +0100140 struct timeval start, stop;
141 struct stats s;
142
143 gettimeofday(&start, NULL);
Pierre Ossmane1f25452015-02-04 14:12:04 +0100144
Pierre Ossmane1f25452015-02-04 14:12:04 +0100145 try {
DRC13cfb512015-02-26 12:24:03 -0600146 cc = new CConn(fn);
Pierre Ossman8ee522a2018-05-29 15:50:08 +0200147 } catch (rdr::Exception& e) {
Pierre Ossman86475a62015-03-03 16:42:15 +0100148 fprintf(stderr, "Failed to open rfb file: %s\n", e.str());
149 exit(1);
150 }
DRC13cfb512015-02-26 12:24:03 -0600151
Pierre Ossman86475a62015-03-03 16:42:15 +0100152 try {
Pierre Ossmane1f25452015-02-04 14:12:04 +0100153 while (true)
154 cc->processMsg();
Pierre Ossman8ee522a2018-05-29 15:50:08 +0200155 } catch (rdr::EndOfStream& e) {
156 } catch (rdr::Exception& e) {
Pierre Ossmane1f25452015-02-04 14:12:04 +0100157 fprintf(stderr, "Failed to run rfb file: %s\n", e.str());
158 exit(1);
159 }
160
Pierre Ossman98d7af92015-11-16 09:37:46 +0100161 gettimeofday(&stop, NULL);
162
163 s.decodeTime = cc->cpuTime;
164 s.realTime = (double)stop.tv_sec - start.tv_sec;
165 s.realTime += ((double)stop.tv_usec - start.tv_usec)/1000000.0;
Pierre Ossmane1f25452015-02-04 14:12:04 +0100166
167 delete cc;
168
Pierre Ossman98d7af92015-11-16 09:37:46 +0100169 return s;
Pierre Ossmane1f25452015-02-04 14:12:04 +0100170}
171
172static void sort(double *array, int count)
173{
174 bool sorted;
175 int i;
176 do {
177 sorted = true;
178 for (i = 1;i < count;i++) {
179 if (array[i-1] > array[i]) {
180 double d;
181 d = array[i];
182 array[i] = array[i-1];
183 array[i-1] = d;
184 sorted = false;
185 }
186 }
187 } while (!sorted);
188}
189
190static const int runCount = 9;
191
192int main(int argc, char **argv)
193{
194 int i;
Pierre Ossman98d7af92015-11-16 09:37:46 +0100195 struct stats runs[runCount];
196 double values[runCount], dev[runCount];
Pierre Ossmane1f25452015-02-04 14:12:04 +0100197 double median, meddev;
198
199 if (argc != 2) {
200 printf("Syntax: %s <rfb file>\n", argv[0]);
201 return 1;
202 }
203
204 // Warmup
205 runTest(argv[1]);
206
207 // Multiple runs to get a good average
208 for (i = 0;i < runCount;i++)
Pierre Ossman98d7af92015-11-16 09:37:46 +0100209 runs[i] = runTest(argv[1]);
Pierre Ossmane1f25452015-02-04 14:12:04 +0100210
Pierre Ossman98d7af92015-11-16 09:37:46 +0100211 // Calculate median and median deviation for CPU usage
212 for (i = 0;i < runCount;i++)
213 values[i] = runs[i].decodeTime;
214
215 sort(values, runCount);
216 median = values[runCount/2];
Pierre Ossmane1f25452015-02-04 14:12:04 +0100217
218 for (i = 0;i < runCount;i++)
Pierre Ossman98d7af92015-11-16 09:37:46 +0100219 dev[i] = fabs((values[i] - median) / median) * 100;
Pierre Ossmane1f25452015-02-04 14:12:04 +0100220
221 sort(dev, runCount);
222 meddev = dev[runCount/2];
223
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100224 printf("CPU time: %g s (+/- %g %%)\n", median, meddev);
Pierre Ossmane1f25452015-02-04 14:12:04 +0100225
Pierre Ossman98d7af92015-11-16 09:37:46 +0100226 // And for CPU core usage
227 for (i = 0;i < runCount;i++)
228 values[i] = runs[i].decodeTime / runs[i].realTime;
229
230 sort(values, runCount);
231 median = values[runCount/2];
232
233 for (i = 0;i < runCount;i++)
234 dev[i] = fabs((values[i] - median) / median) * 100;
235
236 sort(dev, runCount);
237 meddev = dev[runCount/2];
238
239 printf("Core usage: %g (+/- %g %%)\n", median, meddev);
240
Pierre Ossmane1f25452015-02-04 14:12:04 +0100241 return 0;
242}