blob: fe7b0322e6a8cb46a797a5047e447fc4de65ee49 [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>
30
31#include <rdr/Exception.h>
32#include <rdr/FileInStream.h>
33
34#include <rfb/CConnection.h>
35#include <rfb/CMsgReader.h>
36#include <rfb/Decoder.h>
37#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);
52 virtual void setCursor(int, int, const rfb::Point&, void*, void*);
53 virtual void dataRect(const rfb::Rect&, int);
54 virtual void setColourMapEntries(int, int, rdr::U16*);
55 virtual void bell();
56 virtual void serverCutText(const char*, rdr::U32);
57
58public:
59 double cpuTime;
60
61protected:
62 rdr::FileInStream *in;
63 rfb::Decoder *decoders[rfb::encodingMax+1];
64 rfb::ManagedPixelBuffer pb;
65};
66
67CConn::CConn(const char *filename)
68{
69 int i;
70
71 cpuTime = 0.0;
72
73 in = new rdr::FileInStream(filename);
74 setStreams(in, NULL);
75
76 memset(decoders, 0, sizeof(decoders));
77 for (i = 0;i < rfb::encodingMax;i++) {
78 if (!rfb::Decoder::supported(i))
79 continue;
80
81 decoders[i] = rfb::Decoder::createDecoder(i, this);
82 }
83
84 // Need to skip the initial handshake
85 setState(RFBSTATE_INITIALISATION);
86 // That also means that the reader and writer weren't setup
87 setReader(new rfb::CMsgReader(this, in));
88}
89
90CConn::~CConn()
91{
92 int i;
93
94 delete in;
95
96 for (i = 0;i < rfb::encodingMax;i++)
97 delete decoders[i];
98}
99
100void CConn::setDesktopSize(int w, int h)
101{
102 CConnection::setDesktopSize(w, h);
103
104 pb.setSize(cp.width, cp.height);
105}
106
107void CConn::setPixelFormat(const rfb::PixelFormat& pf)
108{
109 // Override format
110 CConnection::setPixelFormat(filePF);
111
112 pb.setPF(cp.pf());
113}
114
115void CConn::setCursor(int, int, const rfb::Point&, void*, void*)
116{
117}
118
119void CConn::dataRect(const rfb::Rect &r, int encoding)
120{
121 if (!decoders[encoding])
122 throw rdr::Exception("Unknown encoding");
123
124 startCpuCounter();
125 decoders[encoding]->readRect(r, &pb);
126 endCpuCounter();
127
128 cpuTime += getCpuCounter();
129}
130
131void CConn::setColourMapEntries(int, int, rdr::U16*)
132{
133}
134
135void CConn::bell()
136{
137}
138
139void CConn::serverCutText(const char*, rdr::U32)
140{
141}
142
143static double runTest(const char *fn)
144{
145 CConn *cc;
146 double time;
147
Pierre Ossmane1f25452015-02-04 14:12:04 +0100148 try {
DRC13cfb512015-02-26 12:24:03 -0600149 cc = new CConn(fn);
Pierre Ossman86475a62015-03-03 16:42:15 +0100150 } catch (rdr::Exception e) {
151 fprintf(stderr, "Failed to open rfb file: %s\n", e.str());
152 exit(1);
153 }
DRC13cfb512015-02-26 12:24:03 -0600154
Pierre Ossman86475a62015-03-03 16:42:15 +0100155 try {
Pierre Ossmane1f25452015-02-04 14:12:04 +0100156 while (true)
157 cc->processMsg();
158 } catch (rdr::EndOfStream e) {
159 } catch (rdr::Exception e) {
160 fprintf(stderr, "Failed to run rfb file: %s\n", e.str());
161 exit(1);
162 }
163
164 time = cc->cpuTime;
165
166 delete cc;
167
168 return time;
169}
170
171static void sort(double *array, int count)
172{
173 bool sorted;
174 int i;
175 do {
176 sorted = true;
177 for (i = 1;i < count;i++) {
178 if (array[i-1] > array[i]) {
179 double d;
180 d = array[i];
181 array[i] = array[i-1];
182 array[i-1] = d;
183 sorted = false;
184 }
185 }
186 } while (!sorted);
187}
188
189static const int runCount = 9;
190
191int main(int argc, char **argv)
192{
193 int i;
194 double times[runCount], dev[runCount];
195 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++)
207 times[i] = runTest(argv[1]);
208
209 // Calculate median and median deviation
210 sort(times, runCount);
211 median = times[runCount/2];
212
213 for (i = 0;i < runCount;i++)
214 dev[i] = fabs((times[i] - median) / median) * 100;
215
216 sort(dev, runCount);
217 meddev = dev[runCount/2];
218
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100219 printf("CPU time: %g s (+/- %g %%)\n", median, meddev);
Pierre Ossmane1f25452015-02-04 14:12:04 +0100220
221 return 0;
222}