blob: 24f660429fab2958bb6feda825edb5a2271f98bc [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 Ossman9312b0e2018-06-20 12:25:14 +020088 setFramebuffer(new rfb::ManagedPixelBuffer(filePF, cp.width(), cp.height()));
Pierre Ossmane1f25452015-02-04 14:12:04 +010089}
90
91void CConn::setPixelFormat(const rfb::PixelFormat& pf)
92{
93 // Override format
94 CConnection::setPixelFormat(filePF);
Pierre Ossmane1f25452015-02-04 14:12:04 +010095}
96
Pierre Ossman6a1a0d02017-02-19 15:48:17 +010097void CConn::setCursor(int, int, const rfb::Point&, const rdr::U8*)
Pierre Ossmane1f25452015-02-04 14:12:04 +010098{
99}
100
Pierre Ossman9f273e92015-11-09 16:34:54 +0100101void CConn::framebufferUpdateStart()
Pierre Ossmane1f25452015-02-04 14:12:04 +0100102{
Pierre Ossman3da238d2015-11-12 12:20:05 +0100103 CConnection::framebufferUpdateStart();
104
Pierre Ossmane1f25452015-02-04 14:12:04 +0100105 startCpuCounter();
Pierre Ossman9f273e92015-11-09 16:34:54 +0100106}
107
108void CConn::framebufferUpdateEnd()
109{
Pierre Ossman3da238d2015-11-12 12:20:05 +0100110 CConnection::framebufferUpdateEnd();
111
Pierre Ossmane1f25452015-02-04 14:12:04 +0100112 endCpuCounter();
113
114 cpuTime += getCpuCounter();
115}
116
117void CConn::setColourMapEntries(int, int, rdr::U16*)
118{
119}
120
121void CConn::bell()
122{
123}
124
125void CConn::serverCutText(const char*, rdr::U32)
126{
127}
128
Pierre Ossman98d7af92015-11-16 09:37:46 +0100129struct stats
130{
131 double decodeTime;
132 double realTime;
133};
134
135static struct stats runTest(const char *fn)
Pierre Ossmane1f25452015-02-04 14:12:04 +0100136{
137 CConn *cc;
Pierre Ossman98d7af92015-11-16 09:37:46 +0100138 struct timeval start, stop;
139 struct stats s;
140
141 gettimeofday(&start, NULL);
Pierre Ossmane1f25452015-02-04 14:12:04 +0100142
Pierre Ossmane1f25452015-02-04 14:12:04 +0100143 try {
DRC13cfb512015-02-26 12:24:03 -0600144 cc = new CConn(fn);
Pierre Ossman8ee522a2018-05-29 15:50:08 +0200145 } catch (rdr::Exception& e) {
Pierre Ossman86475a62015-03-03 16:42:15 +0100146 fprintf(stderr, "Failed to open rfb file: %s\n", e.str());
147 exit(1);
148 }
DRC13cfb512015-02-26 12:24:03 -0600149
Pierre Ossman86475a62015-03-03 16:42:15 +0100150 try {
Pierre Ossmane1f25452015-02-04 14:12:04 +0100151 while (true)
152 cc->processMsg();
Pierre Ossman8ee522a2018-05-29 15:50:08 +0200153 } catch (rdr::EndOfStream& e) {
154 } catch (rdr::Exception& e) {
Pierre Ossmane1f25452015-02-04 14:12:04 +0100155 fprintf(stderr, "Failed to run rfb file: %s\n", e.str());
156 exit(1);
157 }
158
Pierre Ossman98d7af92015-11-16 09:37:46 +0100159 gettimeofday(&stop, NULL);
160
161 s.decodeTime = cc->cpuTime;
162 s.realTime = (double)stop.tv_sec - start.tv_sec;
163 s.realTime += ((double)stop.tv_usec - start.tv_usec)/1000000.0;
Pierre Ossmane1f25452015-02-04 14:12:04 +0100164
165 delete cc;
166
Pierre Ossman98d7af92015-11-16 09:37:46 +0100167 return s;
Pierre Ossmane1f25452015-02-04 14:12:04 +0100168}
169
170static void sort(double *array, int count)
171{
172 bool sorted;
173 int i;
174 do {
175 sorted = true;
176 for (i = 1;i < count;i++) {
177 if (array[i-1] > array[i]) {
178 double d;
179 d = array[i];
180 array[i] = array[i-1];
181 array[i-1] = d;
182 sorted = false;
183 }
184 }
185 } while (!sorted);
186}
187
188static const int runCount = 9;
189
190int main(int argc, char **argv)
191{
192 int i;
Pierre Ossman98d7af92015-11-16 09:37:46 +0100193 struct stats runs[runCount];
194 double values[runCount], dev[runCount];
Pierre Ossmane1f25452015-02-04 14:12:04 +0100195 double median, meddev;
196
197 if (argc != 2) {
198 printf("Syntax: %s <rfb file>\n", argv[0]);
199 return 1;
200 }
201
202 // Warmup
203 runTest(argv[1]);
204
205 // Multiple runs to get a good average
206 for (i = 0;i < runCount;i++)
Pierre Ossman98d7af92015-11-16 09:37:46 +0100207 runs[i] = runTest(argv[1]);
Pierre Ossmane1f25452015-02-04 14:12:04 +0100208
Pierre Ossman98d7af92015-11-16 09:37:46 +0100209 // Calculate median and median deviation for CPU usage
210 for (i = 0;i < runCount;i++)
211 values[i] = runs[i].decodeTime;
212
213 sort(values, runCount);
214 median = values[runCount/2];
Pierre Ossmane1f25452015-02-04 14:12:04 +0100215
216 for (i = 0;i < runCount;i++)
Pierre Ossman98d7af92015-11-16 09:37:46 +0100217 dev[i] = fabs((values[i] - median) / median) * 100;
Pierre Ossmane1f25452015-02-04 14:12:04 +0100218
219 sort(dev, runCount);
220 meddev = dev[runCount/2];
221
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100222 printf("CPU time: %g s (+/- %g %%)\n", median, meddev);
Pierre Ossmane1f25452015-02-04 14:12:04 +0100223
Pierre Ossman98d7af92015-11-16 09:37:46 +0100224 // And for CPU core usage
225 for (i = 0;i < runCount;i++)
226 values[i] = runs[i].decodeTime / runs[i].realTime;
227
228 sort(values, runCount);
229 median = values[runCount/2];
230
231 for (i = 0;i < runCount;i++)
232 dev[i] = fabs((values[i] - median) / median) * 100;
233
234 sort(dev, runCount);
235 meddev = dev[runCount/2];
236
237 printf("Core usage: %g (+/- %g %%)\n", median, meddev);
238
Pierre Ossmane1f25452015-02-04 14:12:04 +0100239 return 0;
240}