SGI Techpubs Library

IRIX 6.5  »  Books  »  Developer  »  
OpenGL on Silicon Graphics Systems
(document number: 007-2392-003 / published: 2005-03-31)    table of contents  |  additional info  |  download
find in page

Appendix A. Benchmarks

This appendix contains a sample program you can use to measure the performance of an OpenGL operation. For an example of how the program can be used with a small graphics applications, see Chapter 17, “Tuning Graphics Applications: Examples”.

/**********************************************************************
 * perf - framework for measuring performance of an OpenGL operation
 *
 * Compile with: cc -o perf -O perf.c -lGL -lX11
 *      
**********************************************************************/


#include <GL/glx.h>
#include <X11/keysym.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <sys/time.h>


char* ApplicationName;
double Overhead = 0.0;
int VisualAttributes[] = { GLX_RGBA, None };
int WindowWidth;
int WindowHeight;


/**********************************************************************
 * GetClock - get current time (expressed in seconds)
**********************************************************************/
double
GetClock(void) {
        struct timeval t;

        gettimeofday(&t);
        return (double) t.tv_sec + (double) t.tv_usec * 1E-6;
        }
/**********************************************************************
 * ChooseRunTime - select an appropriate runtime for benchmarking
**********************************************************************/
double
ChooseRunTime(void) {
        double start;
        double finish;
        double runTime;

        start = GetClock();

        /* Wait for next tick: */
        while ((finish = GetClock()) == start)
                ;
        
        /* Run for 100 ticks, clamped to [0.5 sec, 5.0 sec]: */
        runTime = 100.0 * (finish - start);
        if (runTime < 0.5)
                runTime = 0.5;
        else if (runTime > 5.0)
                runTime = 5.0;

        return runTime;
        }

/**********************************************************************
 * FinishDrawing - wait for the graphics pipe to go idle
 *
 * This is needed to make sure we're not including time from some 
 * previous uncompleted operation in our measurements.  (It's not 
 * foolproof, since we can't eliminate context switches, but we can 
 * assume our caller has taken care of that problem.)
**********************************************************************/
void
FinishDrawing(void) {
        glFinish();
        }

/**********************************************************************
 * WaitForTick - wait for beginning of next system clock tick; return 
 * the time
**********************************************************************/



double
WaitForTick(void) {
        double start;
        double current;

        start = GetClock();

        /* Wait for next tick: */
        while ((current = GetClock()) == start)
                ;

        /* Start timing: */
        return current;
        }

/**********************************************************************
 * InitBenchmark - measure benchmarking overhead
 *
 * This should be done once before each risky change in the 
 * benchmarking environment.  A ``risky'' change is one that might 
 * reasonably be expected to affect benchmarking overhead.  (For 
 * example, changing from a direct rendering context to an indirect 
 * rendering context.)  If all measurements are being made on a single 
 * rendering context, one call should suffice.
**********************************************************************/
void
InitBenchmark(void) {
        double runTime;
        long reps;
        double start;
        double finish;
        double current;

        /* Select a run time appropriate for our timer resolution: */
        runTime = ChooseRunTime();

        /* Wait for the pipe to clear: */
        FinishDrawing();

        /* Measure approximate overhead for finalization and timing 
         * routines 
         */
        reps = 0;
        start = WaitForTick();
        finish = start + runTime;
        do {
                FinishDrawing();
                ++reps;
                } while ((current = GetClock()) < finish);

        /* Save the overhead for use by Benchmark(): */
        Overhead = (current - start) / (double) reps;
        }

/**********************************************************************
 * Benchmark - measure number of caller's operations performed per 
 * second.
 * Assumes InitBenchmark() has been called previously, to initialize
 * the estimate for timing overhead.
**********************************************************************/
double
Benchmark(void (*operation)(void)) {
        double runTime;
        long reps;
        long newReps;
        long i;
        double start;
        double current;

        if (!operation)
                return 0.0;

        /* Select a run time appropriate for our timer resolution: */
        runTime = ChooseRunTime();

        /*
         * Measure successively larger batches of operations until we 
         * find one that's long enough to meet our runtime target:
         */
        reps = 1;
        for (;;) {
                /* Run a batch: */
                FinishDrawing();
                start = WaitForTick();
                for (i = reps; i > 0; --i)
                        (*operation)();
                FinishDrawing();

                

                /* If we reached our target, bail out of the loop: */
                current = GetClock();
                if (current >= start + runTime + Overhead)
                        break;

                /*
                 * Otherwise, increase the rep count and try to reach 
                 * the target on the next attempt:
                 */
                if (current > start)
                        newReps = reps *
                                (0.5 + runTime / (current - start - 
                                                            Overhead));
                else
                        newReps = reps * 2;
                if (newReps == reps)
                        reps += 1;
                else
                        reps = newReps;
                }

        /* Subtract overhead and return the final operation rate: */
        return (double) reps / (current - start - Overhead);
        }

/**********************************************************************
 * Test - the operation to be measured
 *
 * Will be run several times in order to generate a reasonably accurate
 * result.
**********************************************************************/
void
Test(void) {
        /* Replace this code with the operation you want to measure: */
        glColor3f(1.0, 1.0, 0.0);
        glRecti(0, 0, 32, 32);
        }

/**********************************************************************
 * RunTest - initialize the rendering context and run the test
**********************************************************************/
void
RunTest(void) {
        if (Overhead == 0.0)
                InitBenchmark();
        /* Replace this sample with initialization for your test: */

        glClearColor(0.5, 0.5, 0.5, 1.0);
        glClear(GL_COLOR_BUFFER_BIT);

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0.0, WindowWidth, 0.0, WindowHeight, -1.0, 1.0);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        printf("%.2f operations per second\n", Benchmark(Test));
        }

/**********************************************************************
 * ProcessEvents - handle X11 events directed to our window
 *
 * Run the measurement each time we receive an expose event.
 * Exit when we receive a keypress of the Escape key.
 * Adjust the viewport and projection transformations when the window 
 * changes size.
**********************************************************************/
void
ProcessEvents(Display* dpy) {
        XEvent event;
        Bool redraw = 0;

        do {
                char buf[31];
                KeySym keysym;
        
                XNextEvent(dpy, &event);
                switch(event.type) {
                        case Expose:
                                redraw = 1;
                                break;
                        case ConfigureNotify:
                                glViewport(0, 0,
                                        WindowWidth = 
                                                event.xconfigure.width,
                                        WindowHeight = 
                                              event.xconfigure.height);
                                redraw = 1;
                                break;
                        case KeyPress:
                                (void) XLookupString(&event.xkey, buf,
                                        sizeof(buf), &keysym, NULL);
                                switch (keysym) {
                                        case XK_Escape:
                                                exit(EXIT_SUCCESS);
                                        default:
                                                break;
                                        }
                                break;
                        default:
                                break;
                        }
                } while (XPending(dpy));

        if (redraw) RunTest();
        }

/**********************************************************************
 * Error - print an error message, then exit
**********************************************************************/
void
Error(const char* format, ...) {
        va_list args;
        
        fprintf(stderr, "%s:  ", ApplicationName);
        
        va_start(args, format);
        vfprintf(stderr, format, args);
        va_end(args);
        
        exit(EXIT_FAILURE);
        }

/**********************************************************************
 * main - create window and context, then pass control to ProcessEvents
**********************************************************************/
int
main(int argc, char* argv[]) {
        Display *dpy;
        XVisualInfo *vi;
        XSetWindowAttributes swa;
        Window win;
        GLXContext cx;

        ApplicationName = argv[0];

        /* Get a connection: */
        dpy = XOpenDisplay(NULL);
        if (!dpy) Error("can't open display");

        /* Get an appropriate visual: */
        vi = glXChooseVisual(dpy, DefaultScreen(dpy),VisualAttributes);
        if (!vi) Error("no suitable visual");

        /* Create a GLX context: */
        cx = glXCreateContext(dpy, vi, 0, GL_TRUE);

        /* Create a color map: */
        swa.colormap = XCreateColormap(dpy, RootWindow(dpy, 
                                   vi->screen), vi->visual, AllocNone);

        /* Create a window: */
        swa.border_pixel = 0;
        swa.event_mask = ExposureMask | StructureNotifyMask | 
                                                          KeyPressMask;
        win = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 0, 0,
                        300, 300, 0,vi->depth, InputOutput, vi->visual,
                        CWBorderPixel|CWColormap|CWEventMask, &swa);
        XStoreName(dpy, win, "perf");
        XMapWindow(dpy, win);

        /* Connect the context to the window: */
        glXMakeCurrent(dpy, win, cx);

        /* Handle events: */
        while (1) ProcessEvents(dpy);
        }


OpenGL on Silicon Graphics Systems
(document number: 007-2392-003 / published: 2005-03-31)    table of contents  |  additional info  |  download

    Front Matter
    New Features in This Guide
    About This Guide
    Chapter 1. OpenGL on Silicon Graphics Systems
    Chapter 2. OpenGL and X: Getting Started
    Chapter 3. OpenGL and X: Examples
    Chapter 4. OpenGL and X: Advanced Topics
    Chapter 5. Introduction to OpenGL Extensions
    Chapter 6. Resource Control Extensions
    Chapter 7. Vertex Processing Extensions
    Chapter 8. Texturing Extensions
    Chapter 9. Rendering Extensions
    Chapter 10. Imaging Extensions
    Chapter 11. Video Extensions
    Chapter 12. Miscellaneous OpenGL Extensions
    Chapter 13. Vertex and Fragment Program Extensions
    Chapter 14. OpenGL Tools
    Chapter 15. Tuning Graphics Applications: Fundamentals
    Chapter 16. Tuning the Pipeline
    Chapter 17. Tuning Graphics Applications: Examples
    Chapter 18. System-Specific Tuning
    Appendix A. Benchmarks
    Appendix B. Benchmarking Libraries: libpdb and libisfast
    Appendix C. System Support for OpenGL Versions and Extensions
    Appendix D. XFree86 Configuration Specifics
    Index


home/search | what's new | help