From 38a1c70260f3457977f073cc1535a542877e8671 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 20 Dec 2016 12:32:37 +0100 Subject: [PATCH] Add test to measure framebuffer performance --- tests/CMakeLists.txt | 17 ++++ tests/fbperf.cxx | 225 +++++++++++++++++++++++++++++++++++++++++++ tests/util.cxx | 44 +++++++++ tests/util.h | 5 + 4 files changed, 291 insertions(+) create mode 100644 tests/fbperf.cxx diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index bfd69dcd..164660a3 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,3 +16,20 @@ target_link_libraries(encperf test_util rfb) add_executable(hostport hostport.cxx) target_link_libraries(hostport rfb) + +set(FBPERF_SOURCES + fbperf.cxx + ../vncviewer/FLTKPixelBuffer.cxx + ../vncviewer/PlatformPixelBuffer.cxx) +if(WIN32) + set(FBPERF_SOURCES ${FBPERF_SOURCES} ../vncviewer/Win32PixelBuffer.cxx) +elseif(APPLE) + set(FBPERF_SOURCES ${FBPERF_SOURCES} ../vncviewer/OSXPixelBuffer.cxx) +else() + set(FBPERF_SOURCES ${FBPERF_SOURCES} ../vncviewer/X11PixelBuffer.cxx) +endif() +add_executable(fbperf ${FBPERF_SOURCES}) +target_link_libraries(fbperf test_util rfb ${FLTK_LIBRARIES} ${GETTEXT_LIBRARIES}) +if(APPLE) + target_link_libraries(fbperf "-framework Cocoa" "-framework Carbon") +endif() diff --git a/tests/fbperf.cxx b/tests/fbperf.cxx new file mode 100644 index 00000000..53334a6d --- /dev/null +++ b/tests/fbperf.cxx @@ -0,0 +1,225 @@ +/* Copyright 2016 Pierre Ossman 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 + +#include +#include +#include + +#include +#include + +#include "../vncviewer/PlatformPixelBuffer.h" +#include "../vncviewer/FLTKPixelBuffer.h" + +#if defined(WIN32) +#include "../vncviewer/Win32PixelBuffer.h" +#elif defined(__APPLE__) +#include "../vncviewer/OSXPixelBuffer.h" +#else +#include "../vncviewer/X11PixelBuffer.h" +#endif + +#include "util.h" + +class TestWindow: public Fl_Window { +public: + TestWindow(); + ~TestWindow(); + + 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(); +}; + +TestWindow::TestWindow() : + Fl_Window(1024, 768, "Framebuffer Performance Test") +{ + rdr::U32 pixel; + + pixels = 0; + frames = 0; + time = 0; + + try { +#if defined(WIN32) + fb = new Win32PixelBuffer(w(), h()); +#elif defined(__APPLE__) + fb = new OSXPixelBuffer(w(), h()); +#else + fb = new X11PixelBuffer(w(), h()); +#endif + } catch (rdr::Exception& e) { + fb = new FLTKPixelBuffer(w(), h()); + } + + pixel = 0; + fb->fillRect(fb->getRect(), &pixel); +} + +TestWindow::~TestWindow() +{ + delete fb; + + 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(); + + while (fb->isRendering()) + Fl::wait(); + + 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); +} + +static void dotest(TestWindow* win) +{ + struct timeval start; + char s[1024]; + + win->show(); + + gettimeofday(&start, NULL); + while (rfb::msSince(&start) < 10000) + Fl::wait(); + + fprintf(stderr, "Rendering time: %g ms/frame\n", + win->time * 1000.0 / win->frames); + rfb::siPrefix(win->pixels / win->time, + "pixels/s", s, sizeof(s)); + fprintf(stderr, "Rendering rate: %s\n", s); +} + +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"); + + return 0; +} diff --git a/tests/util.cxx b/tests/util.cxx index 4683d351..17a83698 100644 --- a/tests/util.cxx +++ b/tests/util.cxx @@ -24,6 +24,7 @@ #include #else #include +#include #endif #include "util.h" @@ -132,3 +133,46 @@ double getCpuCounter(cpucounter_t c) 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; +} diff --git a/tests/util.h b/tests/util.h index 16f2ba2f..2b8ab4a8 100644 --- a/tests/util.h +++ b/tests/util.h @@ -34,4 +34,9 @@ void endCpuCounter(cpucounter_t c); double getCpuCounter(cpucounter_t c); +void startTimeCounter(void); +void endTimeCounter(void); + +double getTimeCounter(void); + #endif -- 2.39.5