TweetFollow Us on Twitter

Avoiding traps
Volume Number:2
Issue Number:10
Column Tag:Advanced Macing

Reduce Your Time in the Traps!

By Mike Morton, Senior Software Engineer, Lotus Development Corp., Cambridge, MA

Life in the fast lane

The Macintosh ROM subroutines are called with “trap” instructions, intercepted by dispatching software which interprets the trap and calls the routine. This method is very general, providing compatibility with future ROMs and allowing buggy routines to be replaced.

It's also slow, taking about 45 microseconds for the dispatch process. This article tells you a way to avoid the dispatcher without losing its generality. Since the timing differences are measured in microseconds, there's also a discussion of techniques for measuring the time consumed by a piece of code. Also, a program is included to show the alternate way to call the ROM and how to measure the times used by different methods.

Avoiding traps

When a program executes a trap instruction, the 68000 detects the “error” and transfers control to the trap dispatcher pointed to by the longword at $0028. The dispatching software must, among other things:

• preserve some registers on the stack

• fetch the trap instruction from the code

• decide if the trap is a Toolbox or OS call

• look up the trap number to find whether the routine is in RAM or ROM, and what its address is

• handle the “auto-pop” and “pass A0” bits

• call the routine

• restore registers from the stack

Most of this work can be avoided if you know the routine's address and call it directly, but this is a bad idea for two reasons. First, the address may change in future ROMs. Second, Apple distributes “patches” to ROM routines by changing the dispatch table to call new versions in RAM -- if your program “knows” the address, it'll call the old, buggy ROM routines, ignoring the new RAM-based ones.

There is a balance between hardwiring the address and using the trap dispatcher for every call. The Toolbox “GetTrapAddress” function decodes a trap instruction for you and returns the address of the routine, just as the dispatcher does. You can do this decoding just once in your program, save the address, and repeatedly call it later.

The main reason not to bypass the dispatcher is that it saves a few registers across each call. If you're working in assembler, this is no problem -- just save registers yourself, as needed. In most high-level languages, it also won't be a problem, since the registers lost are typically scratch registers: D1, D2, and A2.

Fig. 1 Our TrapTime Utility shows the difference!

A high-level example

First, let's look at the normal way of calling a Toolbox routine: the simple “SetPt” procedure, which sets the coordinates of a Quickdraw “point”. The following example and the timing program are in TML Pascal; they should be easy to convert to other languages.

Most programs include the Quickdraw unit, which declares “setPt” with

procedure SetPt(VAR pt: point; h, v: integer); INLINE $A880;

When you call the routine with the statement

 setPt (myPt, x, y); { set the point }

it pushes the parameters on the stack and executes the instruction $A880 to trap to the dispatcher, which calls the routine. If you want to skip the cost of repeatedly decoding the trap, you can do it once like this:

 var setPtAddr:longint; { addr of setPt }
  
 setPtAddr := getTrapAddress ($A880);

To call this address, declare a new routine like SetPt, but which produces different in-line 68000 code:

procedure mySetPt
 (VAR pt: point; h, v: integer;
 addr: longint);
 INLINE $205F, $4E90;

Note the extra parameter to this routine: the address of the routine to be called. The instructions given in hex after the “INLINE” do a JSR to that address. The result is nearly the same as executing a trap, but faster.

Calling with this interface is almost like a normal call; pass the address as a parameter:

 mySetPt (myPt, x, y, setPtAddr);

This can be used for most Toolbox calls - just declare your own routine (choose any name) with the same parameters plus the address parameter, and include the exact same “INLINE” code after it. Don't forget to initialize the address with GetTrapAddress before calling, or awful things will happen.

Other high-level languages

You should be able to use this method with almost any language which allows you to insert assembler code in your high-level program. Some languages may have trouble calling the ROM directly -- for instance, many C compilers pass parameters differently than ROM routines do. Some C compilers allow you to choose the method of parameter passing; this will allow you to dispense with assembler altogether and just call the routine through a pointer (ask your nearest C guru how to do this).

More straightforward approaches

This approach assumes that “SetPt” is too slow. If you actually need Toolbox operations to be faster, consider writing the code yourself. You can write a procedure or function to assign two integers to the coordinates of a point -- or just do the assignment yourself. For a simple operation, this approach is preferable to spending lots of effort avoiding the trap dispatcher. (The “K.I.S.S.” rule applies here: “Keep It Simple, Stupid.”)

Speed improvements: hard data

Let's get quantitative. Consider four ways to assign to a point:

• the usual trap

• calling the ROM directly with INLINE

• calling your own procedure

• doing the assignment in-line

I wrote all four in Lisa Pascal and found these times on a Mac, and on a Lisa running MacWorks:

Table: Time to assign to a point

(all times in microseconds)

Mac Lisa/MacWorks

Normal “SetPt” trap 67.7 84.9

Pre-decoded call 22.8 25.6

Roll-your-own 34.5 35.2

Assign in-line 4.8 4.8

Writing your own procedure is slower than using the trap routine's address! The ROM is so fast, compared to compiled Pascal, that it's worth the slightly more complicated call. Part of the speed is because the ROM is tightly-coded; part is because the Mac's video refresh slows down code in RAM.

The fastest method is to forget about writing a procedure and do the assignment normally. This is fourteen times faster than using traps to call the ROM! (There's something to be said for the do-it-yourself approach.)

I tried running the program on a Mac Plus, since its ROM dispatch table has been expanded for faster trap calls. The time for a normal trap is 58.9 microseconds, instead of 67.7 microseconds. All the other times are nearly the same.

Speed improvements: summary

First, all this isn't worthwhile for most traps. If you want to speed up disk I/O, resource operations, etc., the microseconds saved at trap time are dwarfed by the amount of time for a disk transfer or to search a large resource. This trick is appropriate only in some situations.

Second, some routines are best done by hand in simple code in your program. ROM tools such as “SetPt” exist for your convenience, not because they're hard to code. If you find they're taking too much time, change them to a few lines of your own code.

But suppose you're trying to draw lines at top speed with repeated “LineTo” calls? Or use one of the simple bit manipulators in a loop? You may find that you can't easily write it yourself, but you can save 45 microseconds by calling into the ROM using a previously determined address. My estimate is that if a trap takes between 200 and 800 microseconds, you should consider skipping the dispatcher.

The timing program

The program “traptime” found the times given in the table. It has four procedures to time methods, and a “getbasetime” procedure to find the overhead of a loop with no calls. You can write a similar program using the same design in nearly any language.

Note that the program prints its results in ticks (60ths of a second) and doesn't compute the time for a loop iteration; I did the conversions to microseconds-per-iteration by hand, rather than trying to get Pascal to do fractional arithmetic.

Timing methods

Unfortunately, doing accurate timings is fraught with problems. This program tries to avoid these. Some points on timings:

• Repeat your measurements to help detect “random” factors. Small discrepancies should be averaged; large ones should be found and removed.

• Be careful when comparing routines: the four timing routines (and the “overhead” routine) are identical except for one section. Keeping this parallel structure makes your program a controlled experiment, helping you time only the differences between procedures.

• Vary the loop size; make sure that your time per iteration converges as your loop gets bigger.

• When waiting for the program, don't move the mouse or fiddle with the keyboard. This causes interrupts and affects the timings.

• I suspect you shouldn't have the disk spinning, nor have a debugger active while timing. (In practice, I can't detect any timing differences due to either of these factors.)

In short, timing is a scientific experiment and is easy to ruin by not controlling the environment carefully.

Conclusion

Bypassing the trap dispatcher can be a valuable technique in a limited number of situations, allowing you to cut about 45 microseconds off the time to call the ROM. It has some drawbacks such as losing register contents, and may be hard to implement in some higher-level languages. In addition, many ROM calls take so long that the savings isn't significant.

Whatever technique you're interesting in optimizing and timing, accurate measurement is a matter of a careful, controlled approach.

{ traptime -- A program to time various methods of doing a toolbox trap:
  The usual method, calling a user-written routine to do the work, doing 
the work in-line, and calling the ROM routine directly without going 
through the trap dispatcher. Times for all routines are written on the 
screen in ticks for a given number of calls, then the number of calls 
is varied for improved accuracy.

  Mike Morton, November 1985. Modified for TML Pascal, June 1986. }

program traptime (output);{ "(output)" lets us do writelns }

{$I MemTypes.ipas  }
{$I QuickDraw.ipas } { we use Quickdraw graphics }
{$I OSIntf.ipas }{ and OS definitions }
{$I ToolIntf.ipas }{ and Toolbox calls }

var         { program-wide variables }
  basetime: longint; { constant overhead for the loop }
  loops: longint;         { number of iterations to time }
  start: longint;         { starting tickcount for timing }
  Event:EventRecord; {simple event loop for cmd-3}
  DoIt: Boolean; {getnextevent boolean}
  Finished:Boolean;{event loop terminator}

{ getbasetime -- Find the time for the loop when nothing is done inside 
it.This tells us the overhead which should be subtracted from other timings. 
}

function getbasetime: longint;
var count: longint;        { loop counter }
begin;
  start := tickcount;        { snapshot starting time }
  for count := 1 to loops do        { loop a bunch of times... }
    ;           { ...doing nothing each time }
  getbasetime := tickcount-start;       { calculate elapsed time }
end;            { function "getbasetime" }

{ usualtime -- Find the time used to call the ROM the usual way.  This, 
and all timing routines, should look as much as possible like "getbasetime". 
}

function usualtime: longint;
var
  count: longint;        { loop counter }
  pt: point;        { point to assign to }
  x, y: integer;         { coordinates to assign to the point }
begin;
  start := tickcount;        { snapshot starting time }
  for count := 1 to loops do        { this time, inside the loop... }
    setpt (pt, x, y);        { ...we do the ROM call }
  usualtime := tickcount-start;          { calculate elapsed time }
end;            { function "usualtime" }


{ setmypt -- This isn't a timing function like the others; it's a replacement 
for the ROM's "setpt" routine, to see how fast we can do it ourselves. 
}
procedure setmypt (VAR pt: point; x, y: integer);
begin;
  pt.h := x; pt.v := y; { assign to the coordinates; easy! }
end;    { procedure "setmypt" }

{ myowntime -- Time assignment using our own procedure. }

function myowntime: longint;
var
  count: longint;        { loop counter }
  pt: point;        { point to assign to }
  x, y: integer;         { coordinates to assign to point }
begin;
  start := tickcount;        { snapshot starting time }
  for count := 1 to loops do        { this time, inside the loop... }
    setmypt (pt, x, y);           { ...we call our own routine }
  myowntime := tickcount-start;          { calculate elapsed time }
end;            { function myowntime }

{ inlintime -- The most straightforward way: we do the assignment in 
the loop. }

function inlintime: longint;
var
  count: longint;        { loop counter }
  pt: point;        { point to assign to }
  x, y: integer;         { coordinates to assign to point }
begin;
  start := tickcount;        { snapshot starting time }
  for count := 1 to loops do        { this time, inside the loop... }
    begin; pt.h := x; pt.v := y; end;   { ...we do assignment here }
  inlintime := tickcount-start;          { calculate elapsed time }
end;            { function inlintime }

{ setptx -- This is another replacement for "setpt".  It takes an extra 
parameter, the previously determined address of "setpt", and calls that 
address, leaving the other parameters for "setpt".  Unfortunately, TMLPascal 
doesn't mimic Lisa Pascal closely enough to allow us to generate more 
than one word of code in a single declaration.  So we have two procedures 
-- these MUST always be used together!  TML says their 2.0
 release of the compiler will be Lisa-compatible on this score, so this 
unsightly workaround won't be needed any more. }

procedure setptx1 (var pt: point; h, v: integer; addr: longint);
      INLINE   $205F; { MOVE.L   (A7)+,A0  
 ; pop routine's address into A0  }
procedure setptx2;
      INLINE   $4E90;{ JSR(A0);  and call that address }

{ gettrtime -- The last and most complicated way of calling the routine. 
 We use the trap address to call it directly. }

function gettrtime: longint;
var
  addr: longint;         { actual address of "setpt" }
  count: longint;        { loop counter }
  pt: point;        { point to assign to }
  x, y: integer;         { coordinates to assign to point }
begin;
  addr := gettrapaddress ($a880);    { find where routine lives }
  start := tickcount;         { snapshot starting time }
  for count := 1 to loops do begin { inside the loop... }
    setptx1 (pt, x, y, addr);          { ...we call on ROM  }
    setptx2;{ (kludge to sneak in 2nd instruction }
  end;
  gettrtime := tickcount-start;              { calculate elapsed time 
}
end;             { function gettrtime }

begin;          { *** main program *** }
  writeln ('If launching from a floppy, wait for it to stop and click 
to begin...');
  while not button do; while button do;      { wait for a click }

  loops := 10000;          { start with a small loop size... }
  while loops <= 1000000 do  { and go through several sizes}
  begin;
    basetime := getbasetime;        { find constant overhead }

    writeln ('number of loops:', loops, '; base time is:', basetime);
    writeln ('time for usual method is..........: ', usualtime - basetime);
    writeln ('time for calling my own routine is: ', myowntime - basetime);
    writeln ('time for doing it in-line is......: ', inlintime - basetime);
    writeln ('time for doing it with gettrapaddr: ', gettrtime - basetime);
    writeln;

    loops := loops * 10;   { loop sizes increase exponentially }
  end;

  flushevents(EveryEvent,0);
   writeln ('click to exit or take snapshot ');
  Repeat
  systemtask;
 DoIt:=GetNextEvent(EveryEvent,Event);
 if DoIt then
 Case Event.what of
  KeyDown: begin end;
  Mousedown: begin Finished:=true; end;
  End;
Until Finished;
end.            { of main program "traptime"  }



!PAS$Xfer

trapspeed
PAS$Library
OSTraps
ToolTraps
$ 
 
AAPL
$100.53
Apple Inc.
+1.37
MSFT
$45.33
Microsoft Corpora
+0.22
GOOG
$586.86
Google Inc.
+4.70

MacTech Search:
Community Search:

Software Updates via MacUpdate

Apple Motion 5.1.2 - Create and customiz...
Apple Motion is designed for video editors, Motion 5 lets you customize Final Cut Pro titles, transitions, and effects. Or create your own dazzling animations in 2D or 3D space, with real-time... Read more
A Better Finder Rename 9.39 - File, phot...
A Better Finder Rename is the most complete renaming solution available on the market today. That's why, since 1996, tens of thousands of hobbyists, professionals and businesses depend on A Better... Read more
PopChar X 6.6 - Floating window shows av...
PopChar X helps you get the most out of your font collection. With its crystal-clear interface, PopChar X provides a frustration-free way to access any font's special characters. Expanded... Read more
MacUpdate Desktop 6.0.2 - Install Mac ap...
MacUpdate Desktop 6 brings seamless 1-click installs and version updates to your Mac. With a free MacUpdate account and MacUpdate Desktop 6, Mac users can now install almost any Mac app on macupdate.... Read more
PDFpenPro 6.3.2 - Advanced PDF toolkit f...
PDFpenPro allows users to edit PDF's easily. Add text, images and signatures. Fill out PDF forms. Merge or split PDF documents. Reorder and delete pages. Even correct text and edit graphics! Create... Read more
PDFpen 6.3.2 - Edit and annotate PDFs wi...
PDFpen allows users to easily edit PDF's. Add text, images and signatures. Fill out PDF forms. Merge or split PDF documents. Reorder and delete pages. Even correct text and edit graphics! Features... Read more
OS X Yosemite 10.10 DP6 - Developer Prev...
Note: This is a Developer Preview. You must be a registered Apple Mac Developer to download this update. You can also sign up for the free OS X Beta Program to download and preview public beta... Read more
Flavours 1.1.15 - Create and apply theme...
Flavours is a Mac application that allow users to create, apply and share beautifully designed themes. Classy Give your Mac a gorgeous new look by applying delicious themes! Easy Unleash your... Read more
EtreCheck 1.9.14 - For troubleshooting y...
EtreCheck is a simple little app to display the important details of your system configuration and allow you to copy that information to the Clipboard. It is meant to be used with Apple Support... Read more
iFFmpeg 4.5 - Convert multimedia files b...
iFFmpeg is a graphical front-end for FFmpeg, a command-line tool used to convert multimedia files between formats. The command line instructions can be very hard to master/understand, so iFFmpeg does... Read more

Latest Forum Discussions

See All

Go to Bed – An Interview With Touchfight...
Touchfight Games is an exciting new indie studio that was co-formed between game journalist and author Nathan Meunier, artist Leonard Kenyon, and programmer Jon Kenyon. Their debut game Go To Bed will be released this fall, and with all the... | Read more »
Assault Vector Review
Assault Vector Review By Rob Thomas on August 19th, 2014 Our Rating: :: SIMPLE STRATEGYUniversal App - Designed for iPhone and iPad While this hex-based warp ride is fine in theory, Assault Vector is a bit too simple to be... | Read more »
Tom Hanks’ Hanx Writer has Taken the App...
Tom Hanks’ Hanx Writer has Taken the App Store by Storm Posted by Jessica Fisher on August 19th, 2014 [ permalink ] iPad Only App - Designed for the iPad | Read more »
It Came from Canada: Galaxy Dash
With its use of well-established tropes like endless flying and sci-fi space shooting, the upcoming Galaxy Dash: Race to the Outer Run most likely won’t confound expectations. However, with its robust amount of opportunities for fun player... | Read more »
PromptSmart Review
PromptSmart Review By Jennifer Allen on August 19th, 2014 Our Rating: :: SNAPPY SPEECHGIVINGUniversal App - Designed for iPhone and iPad Offering you a teleprompter in your pocket, PromptSmart is immensely helpful for those who do... | Read more »
The Firm (Games)
The Firm 1 Device: iOS iPhone Category: Games Price: $.99, Version: 1 (iTunes) Description: RELEASE SPECIAL SALE 50%! Welcome to THE FIRM, Your profil retained our full consideration and we have the pleasure to inform you that your... | Read more »
They Need To Be Fed 3 (Games)
They Need To Be Fed 3 1.0.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0.0 (iTunes) Description: 360 degree gravity platforming is back! Run, jump, collect, avoid enemies and feed yourself to the monster at the... | Read more »
Who Wore it Best? Phantom Flower vs. And...
Who Wore it Best? takes a break from all the bloodshed to check out two decidedly tranquil and nature-loving puzzles games: Phantom Flower and And Then it Rained. [ Who Wore it Best? Phantom Flower vs. And Then it Rained is a post from... | Read more »
Sentinel 4: Dark Star Review
Sentinel 4: Dark Star Review By Jennifer Allen on August 19th, 2014 Our Rating: :: STURDY TOWER DEFENSEUniversal App - Designed for iPhone and iPad After 4 years, the latest entry to the Sentinel series is here. It’s not quite as... | Read more »
TrashEver2 - You can move your selected...
TrashEver2 - You can move your selected notes to trash box. 1.0.0 Device: iOS Universal Category: Productivity Price: $.99, Version: 1.0.0 (iTunes) Description: TrashEver is an application only for throwing away the note of Evernote... | Read more »

Price Scanner via MacPrices.net

15-inch 2.2GHz MacBook Pro on sale for $1899,...
Adorama has the new 15″ 2.2GHz Retina MacBook Pro on sale for $1899 including free shipping plus NY & NJ sales tax only. Their price is $100 off MSRP, and it’s the lowest price available for this... Read more
Mid-Size Tablet Shootout Posted: iPad mini wi...
I ‘m curious about how many iPads Apple is actually selling these days. It’s been widely rumored and anticipated that new models with A8 SoCs, 2 GB of RAM, 8 megapixel cameras, and fingerprint... Read more
The 15 Biggest iPad Air Problems And How To A...
What’s this? Fifteen “biggest” problems with the iPad Air? Does that mean there are a lot of smaller problems as well? Say it isn’t so! My old iPad 2 has manifested no hardware problems in three... Read more
TYLT Syncable-Duo, 2-in-1 USB Cable With Appl...
TYLT has introduced the Syncable-Duo, a universal cable solution for charging and syncing data to smartphones and tablets. The Syncable-Duo eliminates the need for multiple cables by incorporating... Read more
Save up to $140 off MSRP with Apple refurbish...
Apple is offering Certified Refurbished iPad Airs for up to $140 off MSRP. Apple’s one-year warranty is included with each model, and shipping is free. Stock tends to come and go with some of these... Read more
2.5GHz Mac mini on sale for $549, save $50
B&H Photo has the 2.5GHz Mac mini on sale for $549.99 including free shipping. That’s $50 off MSRP, and B&H will also include a free copy of Parallels Desktop software. NY sales tax only. Read more
Chromebooks Are Actually Sometimes A Better C...
Mac360′s Kate MacKenzie notes that when Steve Jobs announced the post-PC era, he was assuming that the dominant post-PC device would be the iPad he was unveiling, or another Apple product like the... Read more
Files-Finder Edition 1.0 app Brings Finder/Ex...
Appsicum’s Files Finder App is designed for iPad users who miss the functionality of the OS X Finder and Windows’ Explorer on their tablet. Files-Finder Edition App is a complete tool having rich... Read more
Apple and Samsung Both Face Growth Declines I...
As the tablet PC market matures and growth slows, the dominance of market leaders Apple and Samsung is also weakening, according to the latest NPD DisplaySearch Monthly Tablet PC Panel Shipment... Read more
Target online offers $50 off iPad Air, $100 o...
Target has iPad Airs on sale for $50 off MSRP and the 16GB iPad mini on sale for $199 on their online store this week only. Choose free shipping or free local store pickup (if available). Prices are... Read more

Jobs Board

Project Manager / Business Analyst, WW *Appl...
…a senior project manager / business analyst to work within our Worldwide Apple Fulfillment Operations and the Business Process Re-engineering team. This role will work Read more
Position Opening at *Apple* - Apple (United...
**Job Summary** As businesses discover the power of Apple computers and mobile devices, it's your job - as a Solutions Engineer - to show them how to introduce these Read more
Position Opening at *Apple* - Apple (United...
**Job Summary** As more and more people discover Apple , they visit our stores seeking ways to incorporate our products into their lives. It's your job, as a Store Read more
Position Opening at *Apple* - Apple (United...
**Job Summary** Being a Business Manager at an Apple Store means you're the catalyst for businesses to discover and leverage the power, ease, and flexibility of Apple Read more
Project Manager / Business Analyst, WW *Appl...
…a senior project manager / business analyst to work within our Worldwide Apple Fulfillment Operations and the Business Process Re-engineering team. This role will work Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.