mirror of
https://github.com/kasmtech/KasmVNC.git
synced 2024-12-01 20:43:12 +01:00
241 lines
5.2 KiB
C++
241 lines
5.2 KiB
C++
|
/* Copyright 2015 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
||
|
*
|
||
|
* This is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* This software is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this software; if not, write to the Free Software
|
||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||
|
* USA.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* This program reads files produced by TightVNC's/TurboVNC's
|
||
|
* compare-encodings. It is basically a dump of the RFB protocol
|
||
|
* from the server side from the ServerInit message and forward.
|
||
|
* It is assumed that the client is using a bgr888 (LE) pixel
|
||
|
* format.
|
||
|
*/
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <math.h>
|
||
|
#include <sys/time.h>
|
||
|
|
||
|
#include <rdr/Exception.h>
|
||
|
#include <rdr/FileInStream.h>
|
||
|
|
||
|
#include <rfb/CConnection.h>
|
||
|
#include <rfb/CMsgReader.h>
|
||
|
#include <rfb/PixelBuffer.h>
|
||
|
#include <rfb/PixelFormat.h>
|
||
|
|
||
|
#include "util.h"
|
||
|
|
||
|
// FIXME: Files are always in this format
|
||
|
static const rfb::PixelFormat filePF(32, 24, false, true, 255, 255, 255, 0, 8, 16);
|
||
|
|
||
|
class CConn : public rfb::CConnection {
|
||
|
public:
|
||
|
CConn(const char *filename);
|
||
|
~CConn();
|
||
|
|
||
|
virtual void setDesktopSize(int w, int h);
|
||
|
virtual void setPixelFormat(const rfb::PixelFormat& pf);
|
||
|
virtual void setCursor(int, int, const rfb::Point&, const rdr::U8*);
|
||
|
virtual void framebufferUpdateStart();
|
||
|
virtual void framebufferUpdateEnd();
|
||
|
virtual void setColourMapEntries(int, int, rdr::U16*);
|
||
|
virtual void bell();
|
||
|
virtual void serverCutText(const char*, rdr::U32);
|
||
|
|
||
|
public:
|
||
|
double cpuTime;
|
||
|
|
||
|
protected:
|
||
|
rdr::FileInStream *in;
|
||
|
};
|
||
|
|
||
|
CConn::CConn(const char *filename)
|
||
|
{
|
||
|
cpuTime = 0.0;
|
||
|
|
||
|
in = new rdr::FileInStream(filename);
|
||
|
setStreams(in, NULL);
|
||
|
|
||
|
// Need to skip the initial handshake
|
||
|
setState(RFBSTATE_INITIALISATION);
|
||
|
// That also means that the reader and writer weren't setup
|
||
|
setReader(new rfb::CMsgReader(this, in));
|
||
|
}
|
||
|
|
||
|
CConn::~CConn()
|
||
|
{
|
||
|
delete in;
|
||
|
}
|
||
|
|
||
|
void CConn::setDesktopSize(int w, int h)
|
||
|
{
|
||
|
CConnection::setDesktopSize(w, h);
|
||
|
|
||
|
setFramebuffer(new rfb::ManagedPixelBuffer(filePF, cp.width, cp.height));
|
||
|
}
|
||
|
|
||
|
void CConn::setPixelFormat(const rfb::PixelFormat& pf)
|
||
|
{
|
||
|
// Override format
|
||
|
CConnection::setPixelFormat(filePF);
|
||
|
}
|
||
|
|
||
|
void CConn::setCursor(int, int, const rfb::Point&, const rdr::U8*)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void CConn::framebufferUpdateStart()
|
||
|
{
|
||
|
CConnection::framebufferUpdateStart();
|
||
|
|
||
|
startCpuCounter();
|
||
|
}
|
||
|
|
||
|
void CConn::framebufferUpdateEnd()
|
||
|
{
|
||
|
CConnection::framebufferUpdateEnd();
|
||
|
|
||
|
endCpuCounter();
|
||
|
|
||
|
cpuTime += getCpuCounter();
|
||
|
}
|
||
|
|
||
|
void CConn::setColourMapEntries(int, int, rdr::U16*)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void CConn::bell()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void CConn::serverCutText(const char*, rdr::U32)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
struct stats
|
||
|
{
|
||
|
double decodeTime;
|
||
|
double realTime;
|
||
|
};
|
||
|
|
||
|
static struct stats runTest(const char *fn)
|
||
|
{
|
||
|
CConn *cc;
|
||
|
struct timeval start, stop;
|
||
|
struct stats s;
|
||
|
|
||
|
gettimeofday(&start, NULL);
|
||
|
|
||
|
try {
|
||
|
cc = new CConn(fn);
|
||
|
} catch (rdr::Exception& e) {
|
||
|
fprintf(stderr, "Failed to open rfb file: %s\n", e.str());
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
while (true)
|
||
|
cc->processMsg();
|
||
|
} catch (rdr::EndOfStream& e) {
|
||
|
} catch (rdr::Exception& e) {
|
||
|
fprintf(stderr, "Failed to run rfb file: %s\n", e.str());
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
gettimeofday(&stop, NULL);
|
||
|
|
||
|
s.decodeTime = cc->cpuTime;
|
||
|
s.realTime = (double)stop.tv_sec - start.tv_sec;
|
||
|
s.realTime += ((double)stop.tv_usec - start.tv_usec)/1000000.0;
|
||
|
|
||
|
delete cc;
|
||
|
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
static void sort(double *array, int count)
|
||
|
{
|
||
|
bool sorted;
|
||
|
int i;
|
||
|
do {
|
||
|
sorted = true;
|
||
|
for (i = 1;i < count;i++) {
|
||
|
if (array[i-1] > array[i]) {
|
||
|
double d;
|
||
|
d = array[i];
|
||
|
array[i] = array[i-1];
|
||
|
array[i-1] = d;
|
||
|
sorted = false;
|
||
|
}
|
||
|
}
|
||
|
} while (!sorted);
|
||
|
}
|
||
|
|
||
|
static const int runCount = 9;
|
||
|
|
||
|
int main(int argc, char **argv)
|
||
|
{
|
||
|
int i;
|
||
|
struct stats runs[runCount];
|
||
|
double values[runCount], dev[runCount];
|
||
|
double median, meddev;
|
||
|
|
||
|
if (argc != 2) {
|
||
|
printf("Syntax: %s <rfb file>\n", argv[0]);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
// Warmup
|
||
|
runTest(argv[1]);
|
||
|
|
||
|
// Multiple runs to get a good average
|
||
|
for (i = 0;i < runCount;i++)
|
||
|
runs[i] = runTest(argv[1]);
|
||
|
|
||
|
// Calculate median and median deviation for CPU usage
|
||
|
for (i = 0;i < runCount;i++)
|
||
|
values[i] = runs[i].decodeTime;
|
||
|
|
||
|
sort(values, runCount);
|
||
|
median = values[runCount/2];
|
||
|
|
||
|
for (i = 0;i < runCount;i++)
|
||
|
dev[i] = fabs((values[i] - median) / median) * 100;
|
||
|
|
||
|
sort(dev, runCount);
|
||
|
meddev = dev[runCount/2];
|
||
|
|
||
|
printf("CPU time: %g s (+/- %g %%)\n", median, meddev);
|
||
|
|
||
|
// And for CPU core usage
|
||
|
for (i = 0;i < runCount;i++)
|
||
|
values[i] = runs[i].decodeTime / runs[i].realTime;
|
||
|
|
||
|
sort(values, runCount);
|
||
|
median = values[runCount/2];
|
||
|
|
||
|
for (i = 0;i < runCount;i++)
|
||
|
dev[i] = fabs((values[i] - median) / median) * 100;
|
||
|
|
||
|
sort(dev, runCount);
|
||
|
meddev = dev[runCount/2];
|
||
|
|
||
|
printf("Core usage: %g (+/- %g %%)\n", median, meddev);
|
||
|
|
||
|
return 0;
|
||
|
}
|