Initial commit

This commit is contained in:
matt
2020-09-20 12:16:44 +00:00
parent 09a4460ddb
commit 408c005d3e
839 changed files with 190481 additions and 0 deletions

6
tests/.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
conv
convperf
decperf
encperf
fbperf
hostport

46
tests/CMakeLists.txt Normal file
View File

@@ -0,0 +1,46 @@
include_directories(${FLTK_INCLUDE_DIR})
include_directories(${GETTEXT_INCLUDE_DIR})
include_directories(${CMAKE_SOURCE_DIR}/common)
add_library(test_util STATIC util.cxx)
add_executable(convperf convperf.cxx)
target_link_libraries(convperf test_util rfb)
add_executable(conv conv.cxx)
target_link_libraries(conv rfb)
add_executable(decperf decperf.cxx)
target_link_libraries(decperf test_util rfb)
add_executable(encperf encperf.cxx)
target_link_libraries(encperf test_util rfb)
add_executable(hostport hostport.cxx)
target_link_libraries(hostport rfb)
set(FBPERF_SOURCES
fbperf.cxx
../vncviewer/PlatformPixelBuffer.cxx
../vncviewer/Surface.cxx)
if(WIN32)
set(FBPERF_SOURCES ${FBPERF_SOURCES} ../vncviewer/Surface_Win32.cxx)
elseif(APPLE)
set(FBPERF_SOURCES
${FBPERF_SOURCES} ../vncviewer/Surface_OSX.cxx
${FBPERF_SOURCES} ../vncviewer/keysym2ucs.c
${FBPERF_SOURCES} ../vncviewer/cocoa.mm)
else()
set(FBPERF_SOURCES ${FBPERF_SOURCES} ../vncviewer/Surface_X11.cxx)
endif()
add_executable(fbperf ${FBPERF_SOURCES})
target_link_libraries(fbperf test_util rfb ${FLTK_LIBRARIES} ${GETTEXT_LIBRARIES})
if(WIN32)
target_link_libraries(fbperf msimg32)
endif()
if(APPLE)
target_link_libraries(fbperf "-framework Cocoa")
target_link_libraries(fbperf "-framework Carbon")
target_link_libraries(fbperf "-framework IOKit")
endif()

361
tests/conv.cxx Normal file
View File

@@ -0,0 +1,361 @@
/* Copyright 2013-2014 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rfb/PixelFormat.h>
static const rdr::U8 pixelRed = 0xf1;
static const rdr::U8 pixelGreen = 0xc3;
static const rdr::U8 pixelBlue = 0x97;
static const int fbWidth = 40;
static const int fbHeight = 30;
static const int fbArea = fbWidth * fbHeight;
// Maximum bpp, plus some room for unaligned fudging
static const int fbMalloc = (fbArea * 4) + 4;
typedef bool (*testfn) (const rfb::PixelFormat&, const rfb::PixelFormat&);
struct TestEntry {
const char *label;
testfn fn;
};
#define min(a,b) (((a) < (b)) ? (a) : (b))
namespace rfb {
void makePixel(const rfb::PixelFormat &pf,
rdr::U8 *buffer)
{
rfb::Pixel p;
p = 0;
p |= (pixelRed >> (8 - pf.redBits)) << pf.redShift;
p |= (pixelGreen >> (8 - pf.greenBits)) << pf.greenShift;
p |= (pixelBlue >> (8 - pf.blueBits)) << pf.blueShift;
// FIXME: Should we reimplement this as well?
pf.bufferFromPixel(buffer, p);
}
bool verifyPixel(const rfb::PixelFormat &dstpf,
const rfb::PixelFormat &srcpf,
const rdr::U8 *buffer)
{
rfb::Pixel p;
int r, g, b;
int re, ge, be;
// FIXME: Should we reimplement this as well?
p = dstpf.pixelFromBuffer(buffer);
r = (p >> dstpf.redShift) & dstpf.redMax;
g = (p >> dstpf.greenShift) & dstpf.greenMax;
b = (p >> dstpf.blueShift) & dstpf.blueMax;
r = (r * 255 + dstpf.redMax/2) / dstpf.redMax;
g = (g * 255 + dstpf.greenMax/2) / dstpf.greenMax;
b = (b * 255 + dstpf.blueMax/2) / dstpf.blueMax;
// The allowed error depends on:
//
// a) The number of bits the format can hold
// b) The number of bits the source format could hold
re = (1 << (8 - min(dstpf.redBits, srcpf.redBits))) - 1;
ge = (1 << (8 - min(dstpf.greenBits, srcpf.greenBits))) - 1;
be = (1 << (8 - min(dstpf.blueBits, srcpf.blueBits))) - 1;
if (abs(r - pixelRed) > re)
return false;
if (abs(g - pixelGreen) > ge)
return false;
if (abs(b - pixelBlue) > be)
return false;
return true;
}
}
using rfb::makePixel;
using rfb::verifyPixel;
static bool testPixel(const rfb::PixelFormat &dstpf,
const rfb::PixelFormat &srcpf)
{
rfb::Pixel p;
rdr::U8 buffer[4];
makePixel(srcpf, buffer);
p = srcpf.pixelFromBuffer(buffer);
p = dstpf.pixelFromPixel(srcpf, p);
memset(buffer, 0, sizeof(buffer));
dstpf.bufferFromPixel(buffer, p);
if (!verifyPixel(dstpf, srcpf, buffer))
return false;
return true;
}
static bool testBuffer(const rfb::PixelFormat &dstpf,
const rfb::PixelFormat &srcpf)
{
int i, x, y, unaligned;
rdr::U8 bufIn[fbMalloc], bufOut[fbMalloc];
// Once aligned, and once unaligned
for (unaligned = 0;unaligned < 2;unaligned++) {
for (i = 0;i < fbArea;i++)
makePixel(srcpf, bufIn + unaligned + i*srcpf.bpp/8);
memset(bufOut, 0, sizeof(bufOut));
dstpf.bufferFromBuffer(bufOut + unaligned, srcpf,
bufIn + unaligned, fbArea);
for (i = 0;i < fbArea;i++) {
if (!verifyPixel(dstpf, srcpf, bufOut + unaligned + i*dstpf.bpp/8))
return false;
}
memset(bufIn, 0, sizeof(bufIn));
for (y = 0;y < fbHeight;y++) {
for (x = 0;x < fbWidth/2;x++)
makePixel(srcpf, bufIn + unaligned + (x + y*fbWidth)*srcpf.bpp/8);
}
memset(bufOut, 0, sizeof(bufOut));
dstpf.bufferFromBuffer(bufOut + unaligned, srcpf, bufIn + unaligned,
fbWidth/2, fbHeight, fbWidth, fbWidth);
for (y = 0;y < fbHeight;y++) {
for (x = 0;x < fbWidth;x++) {
if (x < fbWidth/2) {
if (!verifyPixel(dstpf, srcpf,
bufOut + unaligned + (x + y*fbWidth)*dstpf.bpp/8))
return false;
} else {
const rdr::U8 zero[4] = { 0, 0, 0, 0 };
if (memcmp(bufOut + unaligned + (x + y*fbWidth)*dstpf.bpp/8, zero,
dstpf.bpp/8) != 0)
return false;
}
}
}
}
return true;
}
static bool testRGB(const rfb::PixelFormat &dstpf,
const rfb::PixelFormat &srcpf)
{
int i, x, y, unaligned;
rdr::U8 bufIn[fbMalloc], bufRGB[fbMalloc], bufOut[fbMalloc];
// Once aligned, and once unaligned
for (unaligned = 0;unaligned < 2;unaligned++) {
for (i = 0;i < fbArea;i++)
makePixel(srcpf, bufIn + unaligned + i*srcpf.bpp/8);
memset(bufRGB, 0, sizeof(bufRGB));
srcpf.rgbFromBuffer(bufRGB + unaligned, bufIn + unaligned, fbArea);
memset(bufOut, 0, sizeof(bufOut));
dstpf.bufferFromRGB(bufOut + unaligned, bufRGB + unaligned, fbArea);
for (i = 0;i < fbArea;i++) {
if (!verifyPixel(dstpf, srcpf, bufOut + unaligned + i*dstpf.bpp/8))
return false;
}
memset(bufIn, 0, sizeof(bufIn));
for (y = 0;y < fbHeight;y++) {
for (x = 0;x < fbWidth/2;x++)
makePixel(srcpf, bufIn + unaligned + (x + y*fbWidth)*srcpf.bpp/8);
}
memset(bufRGB, 0, sizeof(bufRGB));
srcpf.rgbFromBuffer(bufRGB + unaligned, bufIn + unaligned,
fbWidth/2, fbWidth, fbHeight);
memset(bufOut, 0, sizeof(bufOut));
dstpf.bufferFromRGB(bufOut + unaligned, bufRGB + unaligned,
fbWidth/2, fbWidth, fbHeight);
for (y = 0;y < fbHeight;y++) {
for (x = 0;x < fbWidth;x++) {
if (x < fbWidth/2) {
if (!verifyPixel(dstpf, srcpf,
bufOut + unaligned + (x + y*fbWidth)*dstpf.bpp/8))
return false;
} else {
const rdr::U8 zero[4] = { 0, 0, 0, 0 };
if (memcmp(bufOut + unaligned + (x + y*fbWidth)*dstpf.bpp/8, zero,
dstpf.bpp/8) != 0)
return false;
}
}
}
}
return true;
}
static bool testPixelRGB(const rfb::PixelFormat &dstpf,
const rfb::PixelFormat &srcpf)
{
rfb::Pixel p;
rdr::U16 r16, g16, b16;
rdr::U8 r8, g8, b8;
rdr::U8 buffer[4];
makePixel(srcpf, buffer);
p = srcpf.pixelFromBuffer(buffer);
srcpf.rgbFromPixel(p, &r16, &g16, &b16);
p = dstpf.pixelFromRGB(r16, g16, b16);
memset(buffer, 0, sizeof(buffer));
dstpf.bufferFromPixel(buffer, p);
if (!verifyPixel(dstpf, srcpf, buffer))
return false;
makePixel(srcpf, buffer);
p = srcpf.pixelFromBuffer(buffer);
srcpf.rgbFromPixel(p, &r8, &g8, &b8);
p = dstpf.pixelFromRGB(r8, g8, b8);
memset(buffer, 0, sizeof(buffer));
dstpf.bufferFromPixel(buffer, p);
if (!verifyPixel(dstpf, srcpf, buffer))
return false;
return true;
}
struct TestEntry tests[] = {
{"Pixel from pixel", testPixel},
{"Buffer from buffer", testBuffer},
{"Buffer to/from RGB", testRGB},
{"Pixel to/from RGB", testPixelRGB},
};
static void doTests(const rfb::PixelFormat &dstpf,
const rfb::PixelFormat &srcpf)
{
size_t i;
char dstb[256], srcb[256];
dstpf.print(dstb, sizeof(dstb));
srcpf.print(srcb, sizeof(srcb));
printf("\n");
printf("%s to %s\n", srcb, dstb);
printf("\n");
for (i = 0;i < sizeof(tests)/sizeof(tests[0]);i++) {
printf(" %s: ", tests[i].label);
fflush(stdout);
if (tests[i].fn(dstpf, srcpf))
printf("OK");
else
printf("FAILED");
printf("\n");
}
}
int main(int argc, char **argv)
{
rfb::PixelFormat dstpf, srcpf;
printf("Pixel Conversion Correctness Test\n");
/* rgb888 targets */
dstpf.parse("rgb888");
srcpf.parse("rgb888");
doTests(dstpf, srcpf);
srcpf.parse("bgr888");
doTests(dstpf, srcpf);
srcpf.parse("rgb565");
doTests(dstpf, srcpf);
srcpf.parse("rgb232");
doTests(dstpf, srcpf);
/* rgb565 targets */
dstpf.parse("rgb565");
srcpf.parse("rgb888");
doTests(dstpf, srcpf);
srcpf.parse("bgr565");
doTests(dstpf, srcpf);
srcpf.parse("rgb232");
doTests(dstpf, srcpf);
/* rgb232 targets */
dstpf.parse("rgb232");
srcpf.parse("rgb888");
doTests(dstpf, srcpf);
srcpf.parse("rgb565");
doTests(dstpf, srcpf);
srcpf.parse("bgr232");
doTests(dstpf, srcpf);
/* endian conversion (both ways) */
dstpf = rfb::PixelFormat(32, 24, false, true, 255, 255, 255, 0, 8, 16);
srcpf = rfb::PixelFormat(32, 24, true, true, 255, 255, 255, 0, 8, 16);
doTests(dstpf, srcpf);
doTests(srcpf, dstpf);
dstpf = rfb::PixelFormat(16, 16, false, true, 31, 63, 31, 0, 5, 11);
srcpf = rfb::PixelFormat(16, 16, true, true, 31, 63, 31, 0, 5, 11);
doTests(dstpf, srcpf);
doTests(srcpf, dstpf);
// Pesky case that is very asymetrical
dstpf = rfb::PixelFormat(32, 24, false, true, 255, 255, 255, 0, 8, 16);
srcpf = rfb::PixelFormat(32, 24, true, true, 255, 255, 255, 0, 24, 8);
doTests(dstpf, srcpf);
doTests(srcpf, dstpf);
}

224
tests/convperf.cxx Normal file
View File

@@ -0,0 +1,224 @@
/* Copyright 2013-2014 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <rfb/PixelFormat.h>
#include "util.h"
static const int tile = 64;
static const int fbsize = 4096;
static rdr::U8 *fb1, *fb2;
typedef void (*testfn) (rfb::PixelFormat&, rfb::PixelFormat&, rdr::U8*, rdr::U8*);
struct TestEntry {
const char *label;
testfn fn;
};
static void testMemcpy(rfb::PixelFormat &dstpf, rfb::PixelFormat &srcpf,
rdr::U8 *dst, rdr::U8 *src)
{
int h;
h = tile;
while (h--) {
memcpy(dst, src, tile * dstpf.bpp/8);
dst += fbsize * dstpf.bpp/8;
src += fbsize * dstpf.bpp/8;
}
}
static void testBuffer(rfb::PixelFormat &dstpf, rfb::PixelFormat &srcpf,
rdr::U8 *dst, rdr::U8 *src)
{
dstpf.bufferFromBuffer(dst, srcpf, src, tile, tile, fbsize, fbsize);
}
static void testToRGB(rfb::PixelFormat &dstpf, rfb::PixelFormat &srcpf,
rdr::U8 *dst, rdr::U8 *src)
{
srcpf.rgbFromBuffer(dst, src, tile, fbsize, tile);
}
static void testFromRGB(rfb::PixelFormat &dstpf, rfb::PixelFormat &srcpf,
rdr::U8 *dst, rdr::U8 *src)
{
dstpf.bufferFromRGB(dst, src, tile, fbsize, tile);
}
static void doTest(testfn fn, rfb::PixelFormat &dstpf, rfb::PixelFormat &srcpf)
{
startCpuCounter();
for (int i = 0;i < 10000;i++) {
int x, y;
rdr::U8 *dst, *src;
x = rand() % (fbsize - tile);
y = rand() % (fbsize - tile);
dst = fb1 + (x + y * fbsize) * dstpf.bpp/8;
src = fb2 + (x + y * fbsize) * srcpf.bpp/8;
fn(dstpf, srcpf, dst, src);
}
endCpuCounter();
float data, time;
data = (double)tile * tile * 10000;
time = getCpuCounter();
printf("%g", data / (1000.0*1000.0) / time);
}
struct TestEntry tests[] = {
{"memcpy", testMemcpy},
{"bufferFromBuffer", testBuffer},
{"rgbFromBuffer", testToRGB},
{"bufferFromRGB", testFromRGB},
};
static void doTests(rfb::PixelFormat &dstpf, rfb::PixelFormat &srcpf)
{
size_t i;
char dstb[256], srcb[256];
dstpf.print(dstb, sizeof(dstb));
srcpf.print(srcb, sizeof(srcb));
printf("%s,%s", srcb, dstb);
for (i = 0;i < sizeof(tests)/sizeof(tests[0]);i++) {
printf(",");
doTest(tests[i].fn, dstpf, srcpf);
}
printf("\n");
}
int main(int argc, char **argv)
{
size_t bufsize;
time_t t;
char datebuffer[256];
size_t i;
bufsize = fbsize * fbsize * 4;
fb1 = new rdr::U8[bufsize];
fb2 = new rdr::U8[bufsize];
for (i = 0;i < bufsize;i++) {
fb1[i] = rand();
fb2[i] = rand();
}
time(&t);
strftime(datebuffer, sizeof(datebuffer), "%Y-%m-%d %H:%M UTC", gmtime(&t));
printf("# Pixel Conversion Performance Test %s\n", datebuffer);
printf("#\n");
printf("# Frame buffer: %dx%d pixels\n", fbsize, fbsize);
printf("# Tile size: %dx%d pixels\n", tile, tile);
printf("#\n");
printf("# Note: Results are Mpixels/sec\n");
printf("#\n");
printf("Source format,Destination Format");
for (i = 0;i < sizeof(tests)/sizeof(tests[0]);i++)
printf(",%s", tests[i].label);
printf("\n");
rfb::PixelFormat dstpf, srcpf;
/* rgb888 targets */
printf("\n");
dstpf.parse("rgb888");
srcpf.parse("rgb888");
doTests(dstpf, srcpf);
srcpf.parse("bgr888");
doTests(dstpf, srcpf);
srcpf.parse("rgb565");
doTests(dstpf, srcpf);
srcpf.parse("rgb232");
doTests(dstpf, srcpf);
/* rgb565 targets */
printf("\n");
dstpf.parse("rgb565");
srcpf.parse("rgb888");
doTests(dstpf, srcpf);
srcpf.parse("bgr565");
doTests(dstpf, srcpf);
srcpf.parse("rgb232");
doTests(dstpf, srcpf);
/* rgb232 targets */
printf("\n");
dstpf.parse("rgb232");
srcpf.parse("rgb888");
doTests(dstpf, srcpf);
srcpf.parse("rgb565");
doTests(dstpf, srcpf);
srcpf.parse("bgr232");
doTests(dstpf, srcpf);
/* rgb565 with endian conversion (both ways) */
printf("\n");
dstpf = rfb::PixelFormat(32, 24, false, true, 255, 255, 255, 0, 8, 16);
srcpf = rfb::PixelFormat(32, 24, true, true, 255, 255, 255, 0, 8, 16);
doTests(srcpf, dstpf);
doTests(dstpf, srcpf);
dstpf = rfb::PixelFormat(16, 16, false, true, 31, 63, 31, 0, 5, 11);
srcpf = rfb::PixelFormat(16, 16, true, true, 31, 63, 31, 0, 5, 11);
doTests(srcpf, dstpf);
doTests(dstpf, srcpf);
return 0;
}

240
tests/decperf.cxx Normal file
View File

@@ -0,0 +1,240 @@
/* 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;
}

507
tests/encperf.cxx Normal file
View File

@@ -0,0 +1,507 @@
/* Copyright 2015 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2015 D. R. Commander. All Rights Reserved.
*
* 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
* fbs-dump, which in turn takes files from rfbproxy. It is
* basically a dump of the RFB protocol from the server side after
* the ServerInit message. Mostly this consists of FramebufferUpdate
* message using the HexTile encoding. Screen size and pixel format
* are not encoded in the file and must be specified by the user.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/time.h>
#include <rdr/Exception.h>
#include <rdr/OutStream.h>
#include <rdr/FileInStream.h>
#include <rfb/PixelFormat.h>
#include <rfb/CConnection.h>
#include <rfb/CMsgReader.h>
#include <rfb/UpdateTracker.h>
#include <rfb/EncodeManager.h>
#include <rfb/SConnection.h>
#include <rfb/SMsgWriter.h>
#include "util.h"
static rfb::IntParameter width("width", "Frame buffer width", 0);
static rfb::IntParameter height("height", "Frame buffer height", 0);
static rfb::IntParameter count("count", "Number of benchmark iterations", 9);
static rfb::StringParameter format("format", "Pixel format (e.g. bgr888)", "");
static rfb::BoolParameter translate("translate",
"Translate 8-bit and 16-bit datasets into 24-bit",
true);
// The frame buffer (and output) is always this format
static const rfb::PixelFormat fbPF(32, 24, false, true, 255, 255, 255, 0, 8, 16);
// Encodings to use
static const rdr::S32 encodings[] = {
rfb::encodingTight, rfb::encodingCopyRect, rfb::encodingRRE,
rfb::encodingHextile, rfb::encodingZRLE, rfb::pseudoEncodingLastRect,
rfb::pseudoEncodingQualityLevel0 + 8,
rfb::pseudoEncodingCompressLevel0 + 2};
class DummyOutStream : public rdr::OutStream {
public:
DummyOutStream();
virtual int length();
virtual void flush();
private:
virtual int overrun(int itemSize, int nItems);
int offset;
rdr::U8 buf[131072];
};
class CConn : public rfb::CConnection {
public:
CConn(const char *filename);
~CConn();
void getStats(double& ratio, unsigned long long& bytes,
unsigned long long& rawEquivalent);
virtual void setDesktopSize(int w, int h);
virtual void setCursor(int, int, const rfb::Point&, const rdr::U8*);
virtual void framebufferUpdateStart();
virtual void framebufferUpdateEnd();
virtual void dataRect(const rfb::Rect&, int);
virtual void setColourMapEntries(int, int, rdr::U16*);
virtual void bell();
virtual void serverCutText(const char*, rdr::U32);
public:
double decodeTime;
double encodeTime;
protected:
rdr::FileInStream *in;
rfb::SimpleUpdateTracker updates;
class SConn *sc;
};
class Manager : public rfb::EncodeManager {
public:
Manager(class rfb::SConnection *conn);
void getStats(double&, unsigned long long&, unsigned long long&);
};
class SConn : public rfb::SConnection {
public:
SConn();
~SConn();
void writeUpdate(const rfb::UpdateInfo& ui, const rfb::PixelBuffer* pb);
void getStats(double&, unsigned long long&, unsigned long long&);
virtual void setAccessRights(AccessRights ar);
virtual void setDesktopSize(int fb_width, int fb_height,
const rfb::ScreenSet& layout);
protected:
DummyOutStream *out;
Manager *manager;
};
DummyOutStream::DummyOutStream()
{
offset = 0;
ptr = buf;
end = buf + sizeof(buf);
}
int DummyOutStream::length()
{
flush();
return offset;
}
void DummyOutStream::flush()
{
offset += ptr - buf;
ptr = buf;
}
int DummyOutStream::overrun(int itemSize, int nItems)
{
flush();
if (itemSize * nItems > end - ptr)
nItems = (end - ptr) / itemSize;
return nItems;
}
CConn::CConn(const char *filename)
{
decodeTime = 0.0;
encodeTime = 0.0;
in = new rdr::FileInStream(filename);
setStreams(in, NULL);
// Need to skip the initial handshake and ServerInit
setState(RFBSTATE_NORMAL);
// That also means that the reader and writer weren't setup
setReader(new rfb::CMsgReader(this, in));
// Nor the frame buffer size and format
rfb::PixelFormat pf;
pf.parse(format);
setPixelFormat(pf);
setDesktopSize(width, height);
sc = new SConn();
sc->cp.setPF((bool)translate ? fbPF : pf);
sc->setEncodings(sizeof(encodings) / sizeof(*encodings), encodings);
}
CConn::~CConn()
{
delete sc;
delete in;
}
void CConn::getStats(double& ratio, unsigned long long& bytes,
unsigned long long& rawEquivalent)
{
sc->getStats(ratio, bytes, rawEquivalent);
}
void CConn::setDesktopSize(int w, int h)
{
rfb::ModifiablePixelBuffer *pb;
CConnection::setDesktopSize(w, h);
pb = new rfb::ManagedPixelBuffer((bool)translate ? fbPF : cp.pf(),
cp.width, cp.height);
setFramebuffer(pb);
}
void CConn::setCursor(int, int, const rfb::Point&, const rdr::U8*)
{
}
void CConn::framebufferUpdateStart()
{
CConnection::framebufferUpdateStart();
updates.clear();
startCpuCounter();
}
void CConn::framebufferUpdateEnd()
{
rfb::UpdateInfo ui;
rfb::PixelBuffer* pb = getFramebuffer();
rfb::Region clip(pb->getRect());
CConnection::framebufferUpdateEnd();
endCpuCounter();
decodeTime += getCpuCounter();
updates.getUpdateInfo(&ui, clip);
startCpuCounter();
sc->writeUpdate(ui, pb);
endCpuCounter();
encodeTime += getCpuCounter();
}
void CConn::dataRect(const rfb::Rect &r, int encoding)
{
CConnection::dataRect(r, encoding);
if (encoding != rfb::encodingCopyRect) // FIXME
updates.add_changed(rfb::Region(r));
}
void CConn::setColourMapEntries(int, int, rdr::U16*)
{
}
void CConn::bell()
{
}
void CConn::serverCutText(const char*, rdr::U32)
{
}
Manager::Manager(class rfb::SConnection *conn) :
EncodeManager(conn)
{
}
void Manager::getStats(double& ratio, unsigned long long& encodedBytes,
unsigned long long& rawEquivalent)
{
StatsVector::iterator iter;
unsigned long long bytes, equivalent;
bytes = equivalent = 0;
for (iter = stats.begin(); iter != stats.end(); ++iter) {
StatsVector::value_type::iterator iter2;
for (iter2 = iter->begin(); iter2 != iter->end(); ++iter2) {
bytes += iter2->bytes;
equivalent += iter2->equivalent;
}
}
ratio = (double)equivalent / bytes;
encodedBytes = bytes;
rawEquivalent = equivalent;
}
SConn::SConn()
{
out = new DummyOutStream;
setStreams(NULL, out);
setWriter(new rfb::SMsgWriter(&cp, out));
manager = new Manager(this);
}
SConn::~SConn()
{
delete manager;
delete out;
}
void SConn::writeUpdate(const rfb::UpdateInfo& ui, const rfb::PixelBuffer* pb)
{
manager->writeUpdate(ui, pb, NULL);
}
void SConn::getStats(double& ratio, unsigned long long& bytes,
unsigned long long& rawEquivalent)
{
manager->getStats(ratio, bytes, rawEquivalent);
}
void SConn::setAccessRights(AccessRights ar)
{
}
void SConn::setDesktopSize(int fb_width, int fb_height,
const rfb::ScreenSet& layout)
{
}
struct stats
{
double decodeTime;
double encodeTime;
double realTime;
double ratio;
unsigned long long bytes;
unsigned long long rawEquivalent;
};
static struct stats runTest(const char *fn)
{
CConn *cc;
struct stats s;
struct timeval start, stop;
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->decodeTime;
s.encodeTime = cc->encodeTime;
s.realTime = (double)stop.tv_sec - start.tv_sec;
s.realTime += ((double)stop.tv_usec - start.tv_usec)/1000000.0;
cc->getStats(s.ratio, s.bytes, s.rawEquivalent);
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 void usage(const char *argv0)
{
fprintf(stderr, "Syntax: %s [options] <rfb file>\n", argv0);
fprintf(stderr, "Options:\n");
rfb::Configuration::listParams(79, 14);
exit(1);
}
int main(int argc, char **argv)
{
int i;
const char *fn;
fn = NULL;
for (i = 1; i < argc; i++) {
if (rfb::Configuration::setParam(argv[i]))
continue;
if (argv[i][0] == '-') {
if (i + 1 < argc) {
if (rfb::Configuration::setParam(&argv[i][1], argv[i + 1])) {
i++;
continue;
}
}
usage(argv[0]);
}
if (fn != NULL)
usage(argv[0]);
fn = argv[i];
}
int runCount = count;
struct stats runs[runCount];
double values[runCount], dev[runCount];
double median, meddev;
if (fn == NULL) {
fprintf(stderr, "No file specified!\n\n");
usage(argv[0]);
}
if (strcmp(format, "") == 0) {
fprintf(stderr, "Pixel format not specified!\n\n");
usage(argv[0]);
}
if (width == 0 || height == 0) {
fprintf(stderr, "Frame buffer size not specified!\n\n");
usage(argv[0]);
}
// Warmup
runTest(fn);
// Multiple runs to get a good average
for (i = 0; i < runCount; i++)
runs[i] = runTest(fn);
// Calculate median and median deviation for CPU usage decoding
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 (decoding): %g s (+/- %g %%)\n", median, meddev);
// And for CPU usage encoding
for (i = 0;i < runCount;i++)
values[i] = runs[i].encodeTime;
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 (encoding): %g s (+/- %g %%)\n", median, meddev);
// And for CPU core usage encoding
for (i = 0;i < runCount;i++)
values[i] = (runs[i].decodeTime + runs[i].encodeTime) / 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 (total): %g (+/- %g %%)\n", median, meddev);
#ifdef WIN32
printf("Encoded bytes: %I64d\n", runs[0].bytes);
printf("Raw equivalent bytes: %I64d\n", runs[0].rawEquivalent);
#else
printf("Encoded bytes: %lld\n", runs[0].bytes);
printf("Raw equivalent bytes: %lld\n", runs[0].rawEquivalent);
#endif
printf("Ratio: %g\n", runs[0].ratio);
return 0;
}

399
tests/fbperf.cxx Normal file
View File

@@ -0,0 +1,399 @@
/* Copyright 2016 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.
*/
#include <math.h>
#include <sys/time.h>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/fl_draw.H>
#include <rdr/Exception.h>
#include <rfb/util.h>
#include "../vncviewer/PlatformPixelBuffer.h"
#include "util.h"
class TestWindow: public Fl_Window {
public:
TestWindow();
~TestWindow();
virtual void start(int width, int height);
virtual void stop();
virtual void draw();
protected:
virtual void flush();
void update();
virtual void changefb();
static void timer(void* data);
public:
unsigned long long pixels, frames;
double time;
protected:
PlatformPixelBuffer* fb;
};
class PartialTestWindow: public TestWindow {
protected:
virtual void changefb();
};
class OverlayTestWindow: public PartialTestWindow {
public:
OverlayTestWindow();
virtual void start(int width, int height);
virtual void stop();
virtual void draw();
protected:
Surface* overlay;
Surface* offscreen;
};
TestWindow::TestWindow() :
Fl_Window(0, 0, "Framebuffer Performance Test"),
fb(NULL)
{
}
TestWindow::~TestWindow()
{
stop();
}
void TestWindow::start(int width, int height)
{
rdr::U32 pixel;
stop();
resize(x(), y(), width, height);
pixels = 0;
frames = 0;
time = 0;
fb = new PlatformPixelBuffer(w(), h());
pixel = 0;
fb->fillRect(fb->getRect(), &pixel);
show();
}
void TestWindow::stop()
{
hide();
delete fb;
fb = NULL;
Fl::remove_idle(timer, this);
}
void TestWindow::draw()
{
int X, Y, W, H;
// We cannot update the damage region from inside the draw function,
// so delegate this to an idle function
Fl::add_idle(timer, this);
// Check what actually needs updating
fl_clip_box(0, 0, w(), h(), X, Y, W, H);
if ((W == 0) || (H == 0))
return;
fb->draw(X, Y, X, Y, W, H);
pixels += W*H;
frames++;
}
void TestWindow::flush()
{
startTimeCounter();
Fl_Window::flush();
#if !defined(WIN32) && !defined(__APPLE__)
// Make sure we measure any work we queue up
XSync(fl_display, False);
#endif
endTimeCounter();
time += getTimeCounter();
}
void TestWindow::update()
{
rfb::Rect r;
startTimeCounter();
changefb();
r = fb->getDamage();
damage(FL_DAMAGE_USER1, r.tl.x, r.tl.y, r.width(), r.height());
#if !defined(WIN32) && !defined(__APPLE__)
// Make sure we measure any work we queue up
XSync(fl_display, False);
#endif
endTimeCounter();
time += getTimeCounter();
}
void TestWindow::changefb()
{
rdr::U32 pixel;
pixel = rand();
fb->fillRect(fb->getRect(), &pixel);
}
void TestWindow::timer(void* data)
{
TestWindow* self;
Fl::remove_idle(timer, data);
self = (TestWindow*)data;
self->update();
}
void PartialTestWindow::changefb()
{
rfb::Rect r;
rdr::U32 pixel;
r = fb->getRect();
r.tl.x += w() / 4;
r.tl.y += h() / 4;
r.br.x -= w() / 4;
r.br.y -= h() / 4;
pixel = rand();
fb->fillRect(r, &pixel);
}
OverlayTestWindow::OverlayTestWindow() :
overlay(NULL), offscreen(NULL)
{
}
void OverlayTestWindow::start(int width, int height)
{
PartialTestWindow::start(width, height);
overlay = new Surface(400, 200);
overlay->clear(0xff, 0x80, 0x00, 0xcc);
// X11 needs an off screen buffer for compositing to avoid flicker,
// and alpha blending doesn't work for windows on Win32
#if !defined(__APPLE__)
offscreen = new Surface(w(), h());
#else
offscreen = NULL;
#endif
}
void OverlayTestWindow::stop()
{
PartialTestWindow::stop();
delete offscreen;
offscreen = NULL;
delete overlay;
overlay = NULL;
}
void OverlayTestWindow::draw()
{
int ox, oy, ow, oh;
int X, Y, W, H;
// We cannot update the damage region from inside the draw function,
// so delegate this to an idle function
Fl::add_idle(timer, this);
// Check what actually needs updating
fl_clip_box(0, 0, w(), h(), X, Y, W, H);
if ((W == 0) || (H == 0))
return;
// We might get a redraw before we are fully ready
if (!overlay)
return;
// Simplify the clip region to a simple rectangle in order to
// properly draw all the layers even if they only partially overlap
fl_push_no_clip();
fl_push_clip(X, Y, W, H);
if (offscreen)
fb->draw(offscreen, X, Y, X, Y, W, H);
else
fb->draw(X, Y, X, Y, W, H);
pixels += W*H;
frames++;
ox = (w() - overlay->width()) / 2;
oy = h() / 4 - overlay->height() / 2;
ow = overlay->width();
oh = overlay->height();
fl_clip_box(ox, oy, ow, oh, X, Y, W, H);
if ((W != 0) && (H != 0)) {
if (offscreen)
overlay->blend(offscreen, X - ox, Y - oy, X, Y, W, H);
else
overlay->blend(X - ox, Y - oy, X, Y, W, H);
}
fl_pop_clip();
fl_pop_clip();
if (offscreen) {
fl_clip_box(0, 0, w(), h(), X, Y, W, H);
offscreen->draw(X, Y, X, Y, W, H);
}
}
static void dosubtest(TestWindow* win, int width, int height,
unsigned long long* pixels,
unsigned long long* frames,
double* time)
{
struct timeval start;
win->start(width, height);
gettimeofday(&start, NULL);
while (rfb::msSince(&start) < 3000)
Fl::wait();
win->stop();
*pixels = win->pixels;
*frames = win->frames;
*time = win->time;
}
static bool is_constant(double a, double b)
{
return (fabs(a - b) / a) < 0.1;
}
static void dotest(TestWindow* win)
{
unsigned long long pixels[3];
unsigned long long frames[3];
double time[3];
double delay, rate;
char s[1024];
// Run the test several times at different resolutions...
dosubtest(win, 800, 600, &pixels[0], &frames[0], &time[0]);
dosubtest(win, 1024, 768, &pixels[1], &frames[1], &time[1]);
dosubtest(win, 1280, 960, &pixels[2], &frames[2], &time[2]);
// ...in order to compute how much of the rendering time is static,
// and how much depends on the number of pixels
// (i.e. solve: time = delay * frames + rate * pixels)
delay = (((time[0] - (double)pixels[0] / pixels[1] * time[1]) /
(frames[0] - (double)pixels[0] / pixels[1] * frames[1])) +
((time[1] - (double)pixels[1] / pixels[2] * time[2]) /
(frames[1] - (double)pixels[1] / pixels[2] * frames[2]))) / 2.0;
rate = (((time[0] - (double)frames[0] / frames[1] * time[1]) /
(pixels[0] - (double)frames[0] / frames[1] * pixels[1])) +
((time[1] - (double)frames[1] / frames[2] * time[2]) /
(pixels[1] - (double)frames[1] / frames[2] * pixels[2]))) / 2.0;
// However, we have some corner cases:
// We are restricted by some delay, e.g. refresh rate
if (is_constant(frames[0]/time[0], frames[2]/time[2])) {
fprintf(stderr, "WARNING: Fixed delay dominating updates.\n\n");
delay = time[2]/frames[2];
rate = 0.0;
}
// There isn't any fixed delay, we are only restricted by pixel
// throughput
if (fabs(delay) < 0.001) {
delay = 0.0;
rate = time[2]/pixels[2];
}
// We can hit cache limits that causes performance to drop
// with increasing update size, screwing up our calculations
if ((pixels[2] / time[2]) < (pixels[0] / time[0] * 0.9)) {
fprintf(stderr, "WARNING: Unexpected behaviour. Measurement unreliable.\n\n");
// We can't determine the proportions between these, so divide the
// time spent evenly
delay = time[2] / 2.0 / frames[2];
rate = time[2] / 2.0 / pixels[2];
}
fprintf(stderr, "Rendering delay: %g ms/frame\n", delay * 1000.0);
if (rate == 0.0)
strcpy(s, "N/A pixels/s");
else
rfb::siPrefix(1.0 / rate, "pixels/s", s, sizeof(s));
fprintf(stderr, "Rendering rate: %s\n", s);
fprintf(stderr, "Maximum FPS: %g fps @ 1920x1080\n",
1.0 / (delay + rate * 1920 * 1080));
}
int main(int argc, char** argv)
{
TestWindow* win;
fprintf(stderr, "Full window update:\n\n");
win = new TestWindow();
dotest(win);
delete win;
fprintf(stderr, "\n");
fprintf(stderr, "Partial window update:\n\n");
win = new PartialTestWindow();
dotest(win);
delete win;
fprintf(stderr, "\n");
fprintf(stderr, "Partial window update with overlay:\n\n");
win = new OverlayTestWindow();
dotest(win);
delete win;
fprintf(stderr, "\n");
return 0;
}

80
tests/hostport.cxx Normal file
View File

@@ -0,0 +1,80 @@
/* Copyright 2016 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.
*/
#include <stdio.h>
#include <rfb/Hostname.h>
static void doTest(const char* hostAndPort,
const char* expectedHost, int expectedPort)
{
char* host;
int port;
printf("\"%s\": ", hostAndPort);
rfb::getHostAndPort(hostAndPort, &host, &port);
if (strcmp(host, expectedHost) != 0)
printf("FAILED (\"%s\" != \"%s\")", host, expectedHost);
else if (port != expectedPort)
printf("FAILED (%d != %d)", port, expectedPort);
else
printf("OK");
printf("\n");
fflush(stdout);
rfb::strFree(host);
}
int main(int argc, char** argv)
{
doTest(":5", "localhost", 5905);
doTest("1.2.3.4", "1.2.3.4", 5900);
doTest("1.2.3.4:5", "1.2.3.4", 5905);
doTest("1.2.3.4:99", "1.2.3.4", 5999);
doTest("1.2.3.4:100", "1.2.3.4", 100);
doTest("1.2.3.4:5901", "1.2.3.4", 5901);
doTest("1.2.3.4::5", "1.2.3.4", 5);
doTest("1.2.3.4::99", "1.2.3.4", 99);
doTest("1.2.3.4::5901", "1.2.3.4", 5901);
doTest("[1.2.3.4]", "1.2.3.4", 5900);
doTest("[1.2.3.4]:5", "1.2.3.4", 5905);
doTest("[1.2.3.4]:100", "1.2.3.4", 100);
doTest("[1.2.3.4]::5", "1.2.3.4", 5);
doTest("[1.2.3.4]::100", "1.2.3.4", 100);
// Ambigiuous. For now we'll keep the old behaviour...
doTest("::1", "localhost", 1);
doTest("2001:1234::20:1", "2001:1234::20:1", 5900);
doTest("[::1]", "::1", 5900);
doTest("[2001:1234::20:1]", "2001:1234::20:1", 5900);
doTest("[2001:1234::20:1]:5", "2001:1234::20:1", 5905);
doTest("[2001:1234::20:1]:99", "2001:1234::20:1", 5999);
doTest("[2001:1234::20:1]:100", "2001:1234::20:1", 100);
doTest("[2001:1234::20:1]:5901", "2001:1234::20:1", 5901);
return 0;
}

View File

@@ -0,0 +1,40 @@
This directory contains the evaluation of the multi-core implementation
in the decoder. The baseline is the performance before the addition of
the DecodeManager class.
Tests were performed on the following systems:
- eLux RP Atom N270 1.6 GHz
- Lubuntu 13.10 i.MX6 Quad 1.2 GHz
- Fedora 22 i7-3770 3.4 GHz
- Windows Vista Core 2 Duo E7400 2.8 GHz
- Windows 10 i3-4170 3.7 GHz
- OS X 10.6 Core 2 Duo 2.53 GHz
- OS X 10.11 i5 2.3 GHz
The systems were tested with:
a) The old, baseline code
b) The new code with all CPUs enabled
c) The new code with only one CPU enabled
The test itself consists of running decperf on the test files from the
TurboVNC project. Rate of decoding is then compared to the baseline.
Note that the CPU time is divided by core usage in the multi CPU cases
in order to derive total decoding time. This method is sensitive to
other load on the system.
On average, there is no regression in performance for single CPU
systems. This however relies on the addition of the single CPU shortcut
in DecodeManager. Without that the performance sees a 10% lower rate.
Dual CPU systems see between 20% and 50% increase, and the quad core
systems between 75% and 125% on average. OS X is an outlier though in
that it gets a mere 32% increase on average. It is unknown why at this
point and tracing doesn't reveal anything obvious. It may be because it
is not a true quad core system, but rather uses HyperThreading.
So in summary, the new code can do a noticeable improvement on decoding
time. However it does so at a cost of efficiency. Four times the CPUs
only gives you about twice the performance. More improvements may be
possible.

Binary file not shown.

View File

@@ -0,0 +1,28 @@
This directory contains the test results in preparation for the removal
of the PixelTransformer class.
Tests were performed on Linux with these CPUs:
- Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz
- ARM i.MX6 DualLite @ 1 GHz
The tests show that the new bufferFromBuffer() has similar performance
as PixelTransformer in most cases. It gets beaten in two cases:
- Input format is 16 BPP and PixelTransformer is in the
non-economical mode (the default mode).
- Input format is 8 BPP, mode irrelevant.
PixelTransformer is about twice as fast in both these cases (more if
converting between two low colour formats).
Although this is significant, it is in cases that are already difficult
to deal with performance wise, and exceedingly rare with modern
hardware. As such it is difficult to motivate the extra complexity that
PixelTransformer requires.
If it turns out that these cases are significant, than we can move
PixelTransformer's massive lookup tables into a shared cache in
PixelFormat. Implementation complexity would be similar, but at least
we would have a friendly API.

View File

@@ -0,0 +1,26 @@
# Pixel Conversion Test 2014-07-09 14:23 UTC
#
# Frame buffer: 4096x4096 pixels
# Tile size: 64x64 pixels
#
# Note: Results are Mpixels/sec
#
Source format,Destination Format,memcpy,PixelTransformer,bufferFromBuffer,rgbFromBuffer,bufferFromRGB
depth 24 (32bpp) little-endian rgb888,depth 24 (32bpp) little-endian rgb888,67.5908,67.3684,66.8189,54.3236,59.1908
depth 24 (32bpp) little-endian bgr888,depth 24 (32bpp) little-endian rgb888,67.5908,33.2468,45.2097,54.3236,58.8506
depth 16 (16bpp) little-endian rgb565,depth 24 (32bpp) little-endian rgb888,62.0606,24.6896,16.8076,22.5924,59.5349
depth 7 (8bpp) rgb232,depth 24 (32bpp) little-endian rgb888,61.6867,63.2099,19.5887,23.5132,59.7956
depth 24 (32bpp) little-endian rgb888,depth 16 (16bpp) little-endian rgb565,96.8321,31.5562,40.3945,54.3236,25.0673
depth 16 (16bpp) little-endian bgr565,depth 16 (16bpp) little-endian rgb565,104.757,31.7766,13.3725,22.5303,25.1443
depth 7 (8bpp) rgb232,depth 16 (16bpp) little-endian rgb565,95.9251,61.594,15.1535,23.5132,25.098
depth 24 (32bpp) little-endian rgb888,depth 7 (8bpp) rgb232,133.42,34.5654,32.6115,54.3236,33.0056
depth 16 (16bpp) little-endian rgb565,depth 7 (8bpp) rgb232,133.42,42.1833,15.7842,22.5303,32.7942
depth 7 (8bpp) bgr232,depth 7 (8bpp) rgb232,137.45,75.7116,16.8699,23.5132,33.0056
depth 24 (32bpp) little-endian bgr888,depth 24 (32bpp) big-endian bgr888,67.5908,33.2738,45.2597,54.3957,58.9353
depth 24 (32bpp) big-endian bgr888,depth 24 (32bpp) little-endian bgr888,67.7025,NaN,45.3097,54.1799,59.0202
depth 16 (16bpp) little-endian bgr565,depth 16 (16bpp) big-endian bgr565,105.567,31.7766,13.8425,21.49,24.9756
depth 16 (16bpp) big-endian bgr565,depth 16 (16bpp) little-endian bgr565,105.84,NaN,12.3746,20.9086,25.1443
1 # Pixel Conversion Test 2014-07-09 14:23 UTC
2 #
3 # Frame buffer: 4096x4096 pixels
4 # Tile size: 64x64 pixels
5 #
6 # Note: Results are Mpixels/sec
7 #
8 Source format,Destination Format,memcpy,PixelTransformer,bufferFromBuffer,rgbFromBuffer,bufferFromRGB
9 depth 24 (32bpp) little-endian rgb888,depth 24 (32bpp) little-endian rgb888,67.5908,67.3684,66.8189,54.3236,59.1908
10 depth 24 (32bpp) little-endian bgr888,depth 24 (32bpp) little-endian rgb888,67.5908,33.2468,45.2097,54.3236,58.8506
11 depth 16 (16bpp) little-endian rgb565,depth 24 (32bpp) little-endian rgb888,62.0606,24.6896,16.8076,22.5924,59.5349
12 depth 7 (8bpp) rgb232,depth 24 (32bpp) little-endian rgb888,61.6867,63.2099,19.5887,23.5132,59.7956
13 depth 24 (32bpp) little-endian rgb888,depth 16 (16bpp) little-endian rgb565,96.8321,31.5562,40.3945,54.3236,25.0673
14 depth 16 (16bpp) little-endian bgr565,depth 16 (16bpp) little-endian rgb565,104.757,31.7766,13.3725,22.5303,25.1443
15 depth 7 (8bpp) rgb232,depth 16 (16bpp) little-endian rgb565,95.9251,61.594,15.1535,23.5132,25.098
16 depth 24 (32bpp) little-endian rgb888,depth 7 (8bpp) rgb232,133.42,34.5654,32.6115,54.3236,33.0056
17 depth 16 (16bpp) little-endian rgb565,depth 7 (8bpp) rgb232,133.42,42.1833,15.7842,22.5303,32.7942
18 depth 7 (8bpp) bgr232,depth 7 (8bpp) rgb232,137.45,75.7116,16.8699,23.5132,33.0056
19 depth 24 (32bpp) little-endian bgr888,depth 24 (32bpp) big-endian bgr888,67.5908,33.2738,45.2597,54.3957,58.9353
20 depth 24 (32bpp) big-endian bgr888,depth 24 (32bpp) little-endian bgr888,67.7025,NaN,45.3097,54.1799,59.0202
21 depth 16 (16bpp) little-endian bgr565,depth 16 (16bpp) big-endian bgr565,105.567,31.7766,13.8425,21.49,24.9756
22 depth 16 (16bpp) big-endian bgr565,depth 16 (16bpp) little-endian bgr565,105.84,NaN,12.3746,20.9086,25.1443

View File

@@ -0,0 +1,26 @@
# Pixel Conversion Test 2014-07-09 14:14 UTC
#
# Frame buffer: 4096x4096 pixels
# Tile size: 64x64 pixels
#
# Note: Results are Mpixels/sec
#
Source format,Destination Format,memcpy,PixelTransformer,bufferFromBuffer,rgbFromBuffer,bufferFromRGB
depth 24 (32bpp) little-endian rgb888,depth 24 (32bpp) little-endian rgb888,568.889,561.096,602.353,338.512,525.128
depth 24 (32bpp) little-endian bgr888,depth 24 (32bpp) little-endian rgb888,561.096,215.579,280.548,338.512,525.128
depth 16 (16bpp) little-endian rgb565,depth 24 (32bpp) little-endian rgb888,602.353,405.545,185.339,146.81,531.948
depth 7 (8bpp) rgb232,depth 24 (32bpp) little-endian rgb888,640,531.948,192.3,170.667,546.133
depth 24 (32bpp) little-endian rgb888,depth 16 (16bpp) little-endian rgb565,853.333,217.872,235.402,344.202,256
depth 16 (16bpp) little-endian bgr565,depth 16 (16bpp) little-endian rgb565,871.489,455.111,89.4323,146.81,256
depth 7 (8bpp) rgb232,depth 16 (16bpp) little-endian rgb565,952.558,568.889,94.8148,167.184,251.288
depth 24 (32bpp) little-endian rgb888,depth 7 (8bpp) rgb232,1107.03,235.402,231.412,341.333,278.639
depth 16 (16bpp) little-endian rgb565,depth 7 (8bpp) rgb232,1137.78,481.882,95.2558,144.735,276.757
depth 7 (8bpp) bgr232,depth 7 (8bpp) rgb232,1204.71,553.514,101.136,169.256,280.548
depth 24 (32bpp) little-endian bgr888,depth 24 (32bpp) big-endian bgr888,568.889,212.228,276.757,338.512,525.128
depth 24 (32bpp) big-endian bgr888,depth 24 (32bpp) little-endian bgr888,576.901,NaN,278.639,338.512,525.128
depth 16 (16bpp) little-endian bgr565,depth 16 (16bpp) big-endian bgr565,890.435,455.111,89.4323,146.81,243.81
depth 16 (16bpp) big-endian bgr565,depth 16 (16bpp) little-endian bgr565,871.489,NaN,85.3333,146.286,254.41
1 # Pixel Conversion Test 2014-07-09 14:14 UTC
2 #
3 # Frame buffer: 4096x4096 pixels
4 # Tile size: 64x64 pixels
5 #
6 # Note: Results are Mpixels/sec
7 #
8 Source format,Destination Format,memcpy,PixelTransformer,bufferFromBuffer,rgbFromBuffer,bufferFromRGB
9 depth 24 (32bpp) little-endian rgb888,depth 24 (32bpp) little-endian rgb888,568.889,561.096,602.353,338.512,525.128
10 depth 24 (32bpp) little-endian bgr888,depth 24 (32bpp) little-endian rgb888,561.096,215.579,280.548,338.512,525.128
11 depth 16 (16bpp) little-endian rgb565,depth 24 (32bpp) little-endian rgb888,602.353,405.545,185.339,146.81,531.948
12 depth 7 (8bpp) rgb232,depth 24 (32bpp) little-endian rgb888,640,531.948,192.3,170.667,546.133
13 depth 24 (32bpp) little-endian rgb888,depth 16 (16bpp) little-endian rgb565,853.333,217.872,235.402,344.202,256
14 depth 16 (16bpp) little-endian bgr565,depth 16 (16bpp) little-endian rgb565,871.489,455.111,89.4323,146.81,256
15 depth 7 (8bpp) rgb232,depth 16 (16bpp) little-endian rgb565,952.558,568.889,94.8148,167.184,251.288
16 depth 24 (32bpp) little-endian rgb888,depth 7 (8bpp) rgb232,1107.03,235.402,231.412,341.333,278.639
17 depth 16 (16bpp) little-endian rgb565,depth 7 (8bpp) rgb232,1137.78,481.882,95.2558,144.735,276.757
18 depth 7 (8bpp) bgr232,depth 7 (8bpp) rgb232,1204.71,553.514,101.136,169.256,280.548
19 depth 24 (32bpp) little-endian bgr888,depth 24 (32bpp) big-endian bgr888,568.889,212.228,276.757,338.512,525.128
20 depth 24 (32bpp) big-endian bgr888,depth 24 (32bpp) little-endian bgr888,576.901,NaN,278.639,338.512,525.128
21 depth 16 (16bpp) little-endian bgr565,depth 16 (16bpp) big-endian bgr565,890.435,455.111,89.4323,146.81,243.81
22 depth 16 (16bpp) big-endian bgr565,depth 16 (16bpp) little-endian bgr565,871.489,NaN,85.3333,146.286,254.41

View File

@@ -0,0 +1,26 @@
# Pixel Conversion Test 2014-07-09 14:14 UTC
#
# Frame buffer: 4096x4096 pixels
# Tile size: 64x64 pixels
#
# Note: Results are Mpixels/sec
#
Source format,Destination Format,memcpy,PixelTransformer,bufferFromBuffer,rgbFromBuffer,bufferFromRGB
depth 24 (32bpp) little-endian rgb888,depth 24 (32bpp) little-endian rgb888,576.901,576.901,546.133,338.512,602.353
depth 24 (32bpp) little-endian bgr888,depth 24 (32bpp) little-endian rgb888,585.143,251.288,288.451,335.738,602.353
depth 16 (16bpp) little-endian rgb565,depth 24 (32bpp) little-endian rgb888,585.143,405.545,205.829,162.54,620.606
depth 7 (8bpp) rgb232,depth 24 (32bpp) little-endian rgb888,493.494,505.679,267.712,177.316,620.606
depth 24 (32bpp) little-endian rgb888,depth 16 (16bpp) little-endian rgb565,999.024,231.412,257.61,344.202,265.974
depth 16 (16bpp) little-endian bgr565,depth 16 (16bpp) little-endian rgb565,975.238,455.111,101.638,165.161,267.712
depth 7 (8bpp) rgb232,depth 16 (16bpp) little-endian rgb565,1050.26,576.901,105.296,181.239,269.474
depth 24 (32bpp) little-endian rgb888,depth 7 (8bpp) rgb232,1638.4,259.24,271.258,347.119,298.978
depth 16 (16bpp) little-endian rgb565,depth 7 (8bpp) rgb232,1575.38,505.679,105.026,165.161,294.676
depth 7 (8bpp) bgr232,depth 7 (8bpp) rgb232,1706.67,602.353,107.225,183.677,298.978
depth 24 (32bpp) little-endian bgr888,depth 24 (32bpp) big-endian bgr888,593.623,251.288,286.434,338.512,620.606
depth 24 (32bpp) big-endian bgr888,depth 24 (32bpp) little-endian bgr888,593.623,NaN,282.483,344.202,611.343
depth 16 (16bpp) little-endian bgr565,depth 16 (16bpp) big-endian bgr565,1050.26,450.11,97.7566,166.504,259.24
depth 16 (16bpp) big-endian bgr565,depth 16 (16bpp) little-endian bgr565,999.024,NaN,96.6038,155.152,267.712
1 # Pixel Conversion Test 2014-07-09 14:14 UTC
2 #
3 # Frame buffer: 4096x4096 pixels
4 # Tile size: 64x64 pixels
5 #
6 # Note: Results are Mpixels/sec
7 #
8 Source format,Destination Format,memcpy,PixelTransformer,bufferFromBuffer,rgbFromBuffer,bufferFromRGB
9 depth 24 (32bpp) little-endian rgb888,depth 24 (32bpp) little-endian rgb888,576.901,576.901,546.133,338.512,602.353
10 depth 24 (32bpp) little-endian bgr888,depth 24 (32bpp) little-endian rgb888,585.143,251.288,288.451,335.738,602.353
11 depth 16 (16bpp) little-endian rgb565,depth 24 (32bpp) little-endian rgb888,585.143,405.545,205.829,162.54,620.606
12 depth 7 (8bpp) rgb232,depth 24 (32bpp) little-endian rgb888,493.494,505.679,267.712,177.316,620.606
13 depth 24 (32bpp) little-endian rgb888,depth 16 (16bpp) little-endian rgb565,999.024,231.412,257.61,344.202,265.974
14 depth 16 (16bpp) little-endian bgr565,depth 16 (16bpp) little-endian rgb565,975.238,455.111,101.638,165.161,267.712
15 depth 7 (8bpp) rgb232,depth 16 (16bpp) little-endian rgb565,1050.26,576.901,105.296,181.239,269.474
16 depth 24 (32bpp) little-endian rgb888,depth 7 (8bpp) rgb232,1638.4,259.24,271.258,347.119,298.978
17 depth 16 (16bpp) little-endian rgb565,depth 7 (8bpp) rgb232,1575.38,505.679,105.026,165.161,294.676
18 depth 7 (8bpp) bgr232,depth 7 (8bpp) rgb232,1706.67,602.353,107.225,183.677,298.978
19 depth 24 (32bpp) little-endian bgr888,depth 24 (32bpp) big-endian bgr888,593.623,251.288,286.434,338.512,620.606
20 depth 24 (32bpp) big-endian bgr888,depth 24 (32bpp) little-endian bgr888,593.623,NaN,282.483,344.202,611.343
21 depth 16 (16bpp) little-endian bgr565,depth 16 (16bpp) big-endian bgr565,1050.26,450.11,97.7566,166.504,259.24
22 depth 16 (16bpp) big-endian bgr565,depth 16 (16bpp) little-endian bgr565,999.024,NaN,96.6038,155.152,267.712

178
tests/util.cxx Normal file
View File

@@ -0,0 +1,178 @@
/* Copyright 2013-2014 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.
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#include <windows.h>
#else
#include <sys/resource.h>
#include <sys/time.h>
#endif
#include "util.h"
#ifdef WIN32
typedef struct {
FILETIME kernelTime;
FILETIME userTime;
} syscounter_t;
#else
typedef struct rusage syscounter_t;
#endif
static syscounter_t _globalCounter[2];
static cpucounter_t globalCounter = _globalCounter;
void startCpuCounter(void)
{
startCpuCounter(globalCounter);
}
void endCpuCounter(void)
{
endCpuCounter(globalCounter);
}
double getCpuCounter(void)
{
return getCpuCounter(globalCounter);
}
cpucounter_t newCpuCounter(void)
{
syscounter_t *c;
c = (syscounter_t*)malloc(sizeof(syscounter_t) * 2);
if (c == NULL)
return NULL;
memset(c, 0, sizeof(syscounter_t) * 2);
return c;
}
void freeCpuCounter(cpucounter_t c)
{
free(c);
}
static void measureCpu(syscounter_t *counter)
{
#ifdef WIN32
FILETIME dummy1, dummy2;
GetProcessTimes(GetCurrentProcess(), &dummy1, &dummy2,
&counter->kernelTime, &counter->userTime);
#else
getrusage(RUSAGE_SELF, counter);
#endif
}
void startCpuCounter(cpucounter_t c)
{
syscounter_t *s = (syscounter_t*)c;
measureCpu(&s[0]);
}
void endCpuCounter(cpucounter_t c)
{
syscounter_t *s = (syscounter_t*)c;
measureCpu(&s[1]);
}
double getCpuCounter(cpucounter_t c)
{
syscounter_t *s = (syscounter_t*)c;
double sysSeconds, userSeconds;
#ifdef WIN32
uint64_t counters[2];
counters[0] = (uint64_t)s[0].kernelTime.dwHighDateTime << 32 |
s[0].kernelTime.dwLowDateTime;
counters[1] = (uint64_t)s[1].kernelTime.dwHighDateTime << 32 |
s[1].kernelTime.dwLowDateTime;
sysSeconds = (double)(counters[1] - counters[0]) / 10000000.0;
counters[0] = (uint64_t)s[0].userTime.dwHighDateTime << 32 |
s[0].userTime.dwLowDateTime;
counters[1] = (uint64_t)s[1].userTime.dwHighDateTime << 32 |
s[1].userTime.dwLowDateTime;
userSeconds = (double)(counters[1] - counters[0]) / 10000000.0;
#else
sysSeconds = (double)(s[1].ru_stime.tv_sec -
s[0].ru_stime.tv_sec);
sysSeconds += (double)(s[1].ru_stime.tv_usec -
s[0].ru_stime.tv_usec) / 1000000.0;
userSeconds = (double)(s[1].ru_utime.tv_sec -
s[0].ru_utime.tv_sec);
userSeconds += (double)(s[1].ru_utime.tv_usec -
s[0].ru_utime.tv_usec) / 1000000.0;
#endif
return sysSeconds + userSeconds;
}
#ifdef WIN32
static LARGE_INTEGER timeStart, timeEnd;
#else
static struct timeval timeStart, timeEnd;
#endif
void startTimeCounter(void)
{
#ifdef WIN32
QueryPerformanceCounter(&timeStart);
#else
gettimeofday(&timeStart, NULL);
#endif
}
void endTimeCounter(void)
{
#ifdef WIN32
QueryPerformanceCounter(&timeEnd);
#else
gettimeofday(&timeEnd, NULL);
#endif
}
double getTimeCounter(void)
{
double time;
#ifdef WIN32
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
time = timeEnd.QuadPart - timeStart.QuadPart;
time = time / freq.QuadPart;
#else
time = (double)timeEnd.tv_sec - timeStart.tv_sec;
time += (double)(timeEnd.tv_usec - timeStart.tv_usec) / 1000000.0;
#endif
return time;
}

42
tests/util.h Normal file
View File

@@ -0,0 +1,42 @@
/* Copyright 2013-2014 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.
*/
#ifndef __TESTS_UTIL_H__
#define __TESTS_UTIL_H__
typedef void* cpucounter_t;
void startCpuCounter(void);
void endCpuCounter(void);
double getCpuCounter(void);
cpucounter_t newCpuCounter(void);
void freeCpuCounter(cpucounter_t c);
void startCpuCounter(cpucounter_t c);
void endCpuCounter(cpucounter_t c);
double getCpuCounter(cpucounter_t c);
void startTimeCounter(void);
void endTimeCounter(void);
double getTimeCounter(void);
#endif