next_inactive up previous


Performance & Timing - HOWTO for Psychtoolbox on OS-X
Draft - Version 0.1 - PTB 1.0.5-MK4 and later

Mario Kleiner

Abstract:

This document is a collection of tips and explanation on how to achieve high drawing performance, accurate visual stimulus presentation timing and accurate presentation timestamps under Psychtoolbox for Mac OS-X, Versions 1.0.5-MK4, 1.0.6 and later. It explains on how to setup your machine for a well running experiment, how to structure your code for maximum performance, how to achieve timed presentation of stimuli and how to check for proper presentation timing. A short introduction into how PTB works internally is also provided. This document is not meant as a comprehensive manual about the Psychtoolbox - Look at the demos and examples provided with PTB or ask your colleagues for a basic introduction.

This document was "hacked together" in a hurry by a person who doesn't like writing user-manuals and is not a native english speaker, so please apologize the bad english and poor structure of this document - after all, it's free.


Contents

1 Introduction

The explanations in this document only apply to the Psychtoolbox for MacOS-X version 1.0.5 with the updated Screen.mexmac file from Mario Kleiner et al. (Version "Build-1.0.5-MK4R1" or later) and all official Psychtoolbox Versions starting at release 1.0.6 or later. The document is in a Draft state, not finished or polished at all and subject to updates in the future, but it should be already useful for your daily work.

The rest of the document is structured as follows: Section 2 gives a brief overview about technical details of the implementation of MacOS-X and of Psychtoolbox and the consequences this will have for your experiments. Section 3 describes how to setup your machine for optimal presentation timing. Section 4.1 describes how you should structure your code for maximum performance and timing accuracy. Section 4.2 describes commands that have been added to PTB 1.0.6 and section 4.2.3 finally explains how to do timed stimulus presentation and how to use the various timestamps returned for proper checking of presentation timing.

Limitation of liability: This document is provided "as is" without any implicit or explicit guarantees for correctness. I made the best effort to summarize what i believe to know (from the internal design of PTB's relevant routines and OS-X, as well as from my own testing) about the optimal way to do things, but in the end you never know what kind of bugs, changes in implementation and side-effects in Psychtoolbox itself, Matlab, MacOS-X and your specific graphics card will interact with each other and the bugs of your experiment to screw up things. So, check your presentation timing carefully and ask at the forum if you get stuck. Good luck!


2 System design

2.1 MacOS-X is not a realtime operating system

MacOS-X is designed by Apple as a general purpose operating system (GP-OS). All existing GP-OS'es have two things in common:

While the first item is a big advantage for users and programmers, item two is a problem if you try to perform visual psychophysics with highly controlled presentation timing at millisecond accuracy. A modern multitasking OS always executes multiple tasks in parallel to your Matlab experiment script: e-mail clients periodically check for - or receive e-mails for you, iTunes has to fetch data over the network or from your harddisk and feed it into the sound driver to play your mp3's or to stream them to other users on the network if "Music sharing" is enabled, virus scanners scan for viruses in the background, the system software update process checks for new updates on the Apple website, the desktop interface has to update the digital clock display every second, any mouse movement triggers the graphics server in order to move the mouse cursor accordingly, Matlab has to blink its cursor, check the current working directory for changed files and check its license if you have a license server installed at your place. And there are multiple internal system processes that have to do background work to keep your system running, e.g., check keyboard and mouse for activity, process network data packets from other computers, manage the virtual memory, write out data to disk so it doesn't get lost on a power failure or system crash. All these processes run in parallel to your experiment and compete for system resources like memory, processor time and also resources on your graphics adaptor. If some of these processes win the race for system resources shortly before the scheduled time of your stimulus onset, it will delay execution of your code and the system will miss the presentation deadline, which leads to skipped frames or screwed up timing, finally to a spoiled trial.

Psychtoolbox tries to reduce interruptions of your Matlab script by other processes as much as possible by switching the Matlab process to realtime priority scheduling - It asks the operating system to give your code as much processing time as it needs, immediately whenever it needs it, prioritizing the needs for processing time of your experiment over the needs of all other system processes. While this mechanism (enabled by use of the Priority() and Rush() commands) significantly reduces the amount of timing jitter and unwanted interruptions, the protection of your script is not perfect - that's why this mode of operation is called soft-realtime in engineering terms. There are multiple ways how the timing of a realtime-script can be screwed up. If your script either voluntarily pauses, e.g., by use of the WaitSecs() command, or if it has to pause because it has to wait for some specific event or activity to happen or complete, e.g., reading of data from harddisk, waiting for the vertical retrace of the display until stimulus-onset can happen, responses from keyboard or mouse, the system will give other processes a bit of processing time, so they can execute while your application is "sleeping". During this slice of time, they can perform actions that will interfere with the execution timing of your script, as soon as it "wakes up" again:

Another problem of the soft-realtime mode: If your script doesn't give up the CPU sometimes for some milliseconds, releasing it to other applications and the operating system, you can interfere with low level system functions that are needed by your script to work properly. E.g., if you don't sleep enough via Screen('Flip') or WaitSecs(), you will prevent the mouse- and keyboard handling routines of the OS from running, so subjects mouse or keyboard responses don't get reported to your script - or they get reported with large random delay, screwing up reaction time measurements!

There is no easy and automatic way that would allow PTB to protect you from any of these sources of timing delays1. Only careful setup and preparation of your computer and Matlab before the experiment and sticking to some programming rules when writing your experiment can reduce these effects to a minimum, minimizing the number of trials that need to be rejected due to messed up presentation timing.

2.2 Screen's use of OpenGL and why you should care...

The "old" Psychtoolboxes for MacOS9 and Windows don't utilize modern graphics hardware. All drawing routines are mostly implemented in code written in the programming language C, that is executing on the computer's main processor (CPU), so the speed of drawing operations is mostly determined by the speed of your computers CPU. The Screen command of the new Psychtoolbox for OS-X (PTB) uses the platform independent graphics library OpenGL for all drawing operations and for control of stimulus onset. This has three advantages compared to the old implementations:

This technical advantages should allow you to:

There are also a few consequences associated with the parallel nature of drawing in PTB:

In order to let the GPU do as much drawing work as possible in parallel to the CPU, you need to submit all drawing commands early in the presentation loop (immediately after the Screen('Flip') command) and you need to tell the GPU when all drawing commands are submitted for the current stimulus. How to do this? See section 4.2.4.


3 Optimal machine setup for experiments

As explained in section 2, a lot of other applications and system processes can interfere with proper execution of your experiment script, despite the use of Priority() and Rush(). The only way to avoid or reduce this interference is by eliminating as many of the distractors as possible:

If you stick to this list of configuration tips, you should get a system with minimum timing interference.


4 Programming tips


4.1 Optimal structure of the code

In order to get the highest drawing performance you should structure your experimental loop to allow for maximum parallelism between CPU and GPU: Stimulus onset is triggered by the Screen('Flip') command. It tells PTB to show the result of all previous drawing operations - your stimulus - to the subject, either at the next possible vertical retrace of the display, or at a specified point in time (actually the closest retrace after that point in time). In that sense, Flip also marks the beginning of the sequence of drawing commands for the next stimulus to show. Therefore you should submit all drawing commands for the next stimulus immediately after the Flip command and before all commands that are unrelated to drawing, e.g., keyboard and mouse checks, Matlab code for experiment logic. This way the GPU can execute drawing as soon as possible and draw your stim while Matlab is executing the remaining commands of your script on the CPU. It also helps if you tell the GPU after the last drawing command that this was the last drawing command to come. That allows PTB and the GPU some further optimizations.

In short, your presentation code in the trial-loop should look roughly like this (How to do it in a loop, e.g., for movie/moving stims, is left as an exercise to the reader)2:

  1. vbl=Screen('Flip', windowPtr, ...) for showing the previously drawn stimulus.
  2. All Matlab commands that need to be synchronized with stimulus onset, e.g., triggering of an acquisition device like fMRI, MEG, EEG, ... or start of sound playback in sync with stimulus onset.
  3. All Screen('xxxxxx', windowPtr, ...) commands for drawing the next stimulus.
  4. Screen('DrawingFinished', windowPtr, ...) to mark the End of all drawing commands - Helps PTB to optimize drawing.
  5. All Matlab commands that are not drawing related, e.g., KbCheck, GetMouse, WaitSecs, experiment control logic...
  6. vbl=Screen('Flip', windowPtr, ...) for showing the new stimulus.
Many simple experiments can do with a different structure (and without step 4) as well. This is just the optimal structure if you want to draw complex, demanding stimuli at high refresh rates and with reliable timing.

The generic layout of your experiment script should look like this:

  1. clear Screen or clear all for clearing out all junk left over from previous runs and to force reinit of Screen.
  2. try

    1. AssertOpenGL - Check if PTB is properly installed on your system.
    2. windowPtr = Screen('OpenWindow', screennumber, 0, [], 32, 2);
    3. All kind of generic setup code for your experiment.
    4. Priority(9); Enable realtime-scheduling
    5. ifi = Screen('GetFlipInterval', windowPtr, 200);
    6. Priority(0); Disable realtime-scheduling
    7. Compute intense setup work, e.g., loading of images from disk, precomputing stuff
    8. Priority(9); Enable realtime-scheduling for real trial
    9. vbl = Screen('Flip', windowPtr, ...); Initially synchronize with retrace, take base time in vbl
    10. for - loop for stimulus presentation or your trial code (see above for optimal code layout)
    11. Screen('CloseAll'); Close display windows
    12. Priority(0); Shutdown realtime mode.
    13. Remaining cleanup code, e.g., writing of result file.
  3. catch

    1. Screen('CloseAll'); Close display windows
    2. Priority(0); Shutdown realtime mode.
    3. ShowCursor; Show cursor again, if it has been disabled.
  4. end;
  5. End of experiment.
Step 1 makes sure that PTB gets reset to a well defined state and that you don't waste Matlab memory with junk from previous activity. Steps 2,3-a,3-b,3-c and 4 make sure that you get your Matlab window back and things properly cleaned up in case of an error. 2-b Opens the window in the recommended way. Steps 2def are optional, they allow to do an extra calibration run to get an extra accurate estimate of the real monitor refresh interval in the variable ifi.

The following subsection will explain specific commands that are relevant for experiment setup and for control of presentation timing. Please see the example code and the online-help of Screen3 for more detailed usage info.

Another special consideration: Put text drawing commands (Screen('DrawText', ...)) at the end of all drawing commands. They are the slowest and could stall the faster commands, because they involve significant processing by the CPU as well.


4.2 Special commands and their usage

4.2.1 Screen('OpenWindow')

The windowPtr=Screen('OpenWindow', screennr, [,color] [,rect][,depth][,buffers][,stereo]); has multiple functions in PTB:

  1. It opens a fullscreen window on the physical display with the logical number screennr. It will also make sure that no other application can do any drawing operations on that physical display. The window would have a background color color, a size rect and a color depth of depth bits per pixel, in reality the color and rect arguments are ignored and specifying anything else than 32 as depth argument will return an error. The buffers argument defines on how many drawing surfaces to use. Any value except 2 - which is the default - will trigger a warning on the Matlab window and a visual flashing yellow warning sign to tell you that you should use other values only for debugging if you are a developer of the PTB itself. The stereo argument allows you to enable a stereoscopic display mode: The default value of 0 will just show a monoscopic display window. A value of 1 will enable MacOS-X's built-in stereo display facilities - Field sequential stereo. OS-X will automatically flip the display at each video refresh between the stimulus for the left-eye and the stimulus for the right-eye, while simultaneously generating appropriate control signals for stereo-goggles and other stereo display hardware supported by Apple. See subsection TODO for information on how to specify the content for left- vs. right eye. This mode only works on some models of graphics hardware - you'll have to try it out. In the future, values greater than one might be implemented to support other stereo display modes like anaglyph stereo and such.
  2. It performs a measurement loop for estimating the real monitor refresh interval: The refresh rate reported by Screen('FrameRate') and Screen('NominalFrameRate') is the value returned by the operating systems. On flat-panels, this values is pretty often unavailable (=reported as zero). On any kind of display, this value may deviate a bit from the real value due to manufacturing tolerances of graphics hardware and multiple other factors. Therefore the measurement loop measures the duration of at least 50 valid consecutive monitor refresh intervals and computes an average. The monitor refresh interval that results from this measurement can be queried via Screen('GetFlipInterval').
  3. It performs a couple of checks to make sure that synchronization to the vertical retrace, queries of rasterbeam positions and a couple of other timing related functions work properly on your specific setup. You will see a blue screen for multiple seconds while this checks are performed. If a check fails or gives potentially troublesome results, PTB will flash a big yellow or red warning triangle on your display and provide a detailed trouble report on the Matlab command window, together with troubleshooting tips.
    On multi-display setups where the displays run at the same monitor refresh interval, some of these crucial checks can fail! In order to make still sure that synchronization to the vertical retrace works properly, a perceptual test is automatically run for 10 seconds, whenever a multi-display setup is detected. You should see something like in figure TODO on your stimulus display, if syncing properly works: The huge gray area flickers in a homogeneous way, you don't see any yellow horizontal lines at the right border of the display, or only a few isolated lines, or a couple of dense yellow lines at the top of the display. If syncing doesn't work properly4, you should instead see something like in figure TODO: Many yellow lines spread over the middle or bottom part of the display or even over the whole height of the display. The gray area is flickering in a very inhomogeneous way - showing massive tearing artifacts. This means that syncing to retrace is broken and you need to perform the troubleshooting tips that PTB outputs to the Matlab window - or set your displays to different refresh rates and rerun, in case PTB doesn't detect trouble, or contact the forum if you're unsure what to do.


4.2.2 Screen('GetFlipInterval')

The ifi = Screen('GetFlipInterval', windowPtr[, numSamples][,stddev][,timeout]); command allows you to query a measured estimate of the real monitor refresh interval that was computed when opening the window, or to rerun the measurement loop with more samples or tighter constraints if you want the best possible estimate. If called as ifi=Screen('GetFlipInterval', windowPtr); it just returns the estimated interframe-intervall ifi from initial calibration. If called with the numSamples argument greater than zero, it will rerun the calibration loop, trying to take at least numSamples valid samples of monitor refresh, with a maximum standard deviation from the mean smaller than stddev (default is 50 microseconds). The loop will abort after at most timeout seconds, in case your system is too noisy to allow a measurement satisfying the given constraints. ifi plays a special role for timed stimulus presentation via the Screen('Flip') command.


4.2.3 Screen('Flip')

The [vbltime sostime fliptime missed beampos] = Screen('Flip', windowPtr [,when] [,clearmode] [,dontsync]); command has five functions in PTB:

Timed stimulus presentation can be done in two ways, depending on the when argument passed to Flip:

  1. If you set when=0 or leave it away, Flip will try to show your stimulus at the next possible vertical retrace of your display. This is the behaviour of all Psychtoolboxes up to (and including) version 1.0.5. Stimulus onset is always in sync with the vertical retrace, as this is a built-in feature of modern graphics hardware, completely independent of any possible timing delays in the rest of the system. But you can still miss stimulus onset on the next possible retrace (skipped frame) if you tried to draw too much in a single monitor refresh interval, so PTB cannot complete drawing of your stimulus in time. In that case, the stimulus will be shown at the first possible vertical retrace after the stimulus is ready for presentation.
  2. If you set when to a value greater than zero, Flip will pause execution until the system time reaches the value when (specified in seconds). Then it will try to show your stimulus in sync with the next possible vertical retrace. It will also perform some internal optimizations to try its best to meet the requested stimulus presentation deadline when. Method 2 is the recommended way of using Flip, method 1 is only available for backward-compatibility with old versions.
    Use of the when value allows you to recover the functionality of the Screen('WaitBlanking', windowPtr, waitframes) command known from the old MacOS-9 PTB. The following snippet of code would show a new stimulus exactly 10 monitor refresh intervals after onset of the last stimulus:
    ifi=Screen('GetFlipInterval', windowPtr);
    % Record current system time as a reference time:
    starttime=GetSecs();
    % Draw first stimulus...
    ...
    % Show first stimulus approximately 30 seconds after time 'starttime', record time of real stimulus onset in vbl:
    vbl=Screen('Flip', windowPtr, starttime + 30);
    % Draw second stimulus
    ...
    % Show second stimulus *exactly* 10 monitor refresh intervals after onset of first stimulus:
    vbl=Screen('Flip', windowPtr, vbl + 10*ifi - 0.5*ifi);
    % Real time of onset of second stimulus is returned in 'vbl'

    The when parameter therefore allows you timing in absolute time units (seconds of system time) or relative to some point in time (starttime + 30 seconds), or some number of monitor refresh intervals after the last stimulus onset via the formula:
    when=vbl + (waitframes - 0.5)*ifi

Synchronization of Matlabs execution to the stimulus onset is enabled by default: Flip waits for stimulus onset to happen - Matlab is paused during this time. Synchronization of Matlab to stimulus onset can be disabled by setting the dontsync value to 1 - Stimulus onset will still happen in sync with retrace, but Matlab won't wait for it to happen and all reported timestamps will be invalid. The value dontsync=2 will completely disable any synchronization of drawing or execution to the retrace - Fast, but will likely create severe flicker and tearing artifacts.

The clearmode flag allows you to specify what should happen after a Flip:

  1. A value of clearmode=0 (the default setting) will clear the drawing surface to the background color, so you can draw a completely new stimulus.
  2. A value of clearmode=1 will restore the drawing surface to exactly the same state as before the flip, so you can incrementally update your stimulus.
  3. A value of clearmode=2 will save you some millisecond(s) of time by leaving the drawing surface in an undefined state - and leaving the job of reinitializing the surface to you.
Flip will also take and (optionally) return multiple time stamps that allow you to measure the time of stimulus onset:

For calculation of vbltime and sostime, PTB takes a high-resolution measurement of system time and of the current vertical position of your display's rasterbeam. It then corrects the timestamp by some correction value calculated from the beam-position, the height of your display and the exact monitor refresh interval. This way, vbltime is always locked to the time of start of vertical retrace, independent of possible timing jitter caused by Matlab or the operating system.

These timestamps should allow you to accurately check your stimulus presentation timing. Flip also contains a built-in check for missed presentation deadlines (when value) and skipped frames. This detector will spot skipped frames and deadlines reliably if you provide a when value greater zero, it will spot many, but not all, skipped frames if you don't provide a when value. The result of the check for skipped frames is returned in the missed value: Positive missed values indicate a missed when deadline or skipped frame - Flip couldn't flip at the vertical retrace closest to the specified when value. A summary of skipped frames is also printed to the Matlab command window at the end of your experiment. PLEASE NOTE THAT THE SKIPPED FRAME DETECTOR IS ONLY AN ADDITIONAL SAFEGUARD FOR DETECTING TIMING PROBLEMS. You are responsible for checking your timing by your own independent tests as well, if frame-accurate timing matters for your study.


4.2.4 Screen('DrawingFinished')

See VBLSyncTest.m and online help Screen DrawingFinished? for now...


4.2.5 Screen('SelectStereoDrawbuffer')

The Screen('SelectStereoDrawbuffer', windowPtr, bufferid) command selects the drawing surface for drawing stimuli when stereo display mode is enabled. In stereo display mode, you have to draw two stimulus images each time before calling Screen('Flip'), one for the left-eye, one for the right-eye. The bufferid argument selects the target buffer for following drawing operations: bufferid=0 - Left eye , bufferid=1 - Right Eye. The selection stays active until the next Flip command and is reset to the left-eye after a flip.

To be continued - Stay tuned...

About this document ...

Performance & Timing - HOWTO for Psychtoolbox on OS-X
Draft - Version 0.1 - PTB 1.0.5-MK4 and later

This document was generated using the LaTeX2HTML translator Version 2002 (1.62)

Copyright © 1993, 1994, 1995, 1996, Nikos Drakos, Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999, Ross Moore, Mathematics Department, Macquarie University, Sydney.

The command line arguments were:
latex2html -no_subdir -split 0 -show_section_numbers /tmp/lyx_tmpdir5791OnE22c/lyx_tmpbuf0/PTB2005.tex

The translation was initiated by Mario Kleiner on 2005-05-18


Footnotes

... delays1
BTW: The same applies to the old PTB on Microsoft Windows and to a smaller degree on MacOS-9. Only some specially configured versions of GNU/Linux ("Realtime Linux") and some commercial - and hard to program - realtime operating systems like, e.g., QNX, would be able to avoid these problems and provide real hard-realtime, but PTB is currently not available for Linux or such systems...
...2
A perfect, well documented, albeit extremely simple example is the VBLSyncTest script. Run it, read its sourcecode carefully.
... Screen3
Online help for Screen subcommand foo is displayed when typing Screen foo? at the Matlab command prompt, e.g., Screen Flip?
... properly4
This can easily happen with all ATI graphics adaptors when run under MacOS-X 10.3 "Panther" or under MacOS-X 10.4.0 "Tiger" due to a bug in the ATI display drivers.

next_inactive up previous
Mario Kleiner 2005-05-18