Article View: comp.lang.modula2
Article #2677TopSpeed and assembler
From: Marco van de Voort
Date: Tue, 01 Aug 1995 22:49
Date: Tue, 01 Aug 1995 22:49
100 lines
7047 bytes
7047 bytes
Hallo Peter!
Monday July 03 1995 00:43, Peter Moylan wrote to All:
PM> assembly language. This is because assembly language allows you
PM> to do anything of which the processor is capable, whereas with a
PM> high-level language like Modula-2 you're stuck with the translations
PM> supplied by the compiler. Most compilers these days are reasonably
PM> good at "code optimisation", i.e. finding a good sequence of
PM> machine language instructions to accomplish what you've specified,
PM> but there will always be optimisations that an assembly language
PM> programmer will find but the compiler will miss.
When I translate TopSpeed stuff to assembler the size reduction varies between
1/6 (small procedures) and 60% (extreme example, but true!) for larger procedures. Very big and very small procedures are the hardest to optimize. The middle length are the easiest to optimize, because most data can be held in registers.
When I see the code generation of TopSpeed, something directly draws my attention. The compiler often uses so called local variables when not necessary, often one or two pushes and pop's would be sufficient.
The speed gain was between M2 : asm like
1 : 1.15 (small string routines)
1 : 3 (Crc32 routines).
1 : 5 (calculation of unix dates)
1 : 10 ( Reading/writing font's with out's and in, stosb, loop construction)
So it isn't nonsens to think about assembler. I only started with 80x86 assembly between 3 weeks and a month ago..(But did assembler on the C-64), and I can
already write quite difficult routines (more then just a int call or so), like the crt module I mentioned often enough.
Besides some extreme examples (like the font routine mentioned above) the main gains I get are archieved by
- rearranging expressions and using registers smartly. I however agree that it is hard to improve this more. It costs me sometimes tens of minutes to figure it out, and I can't see how you could implement this kind of
optimalisations within a compiler.
I'm already amazed by what the TopSpeed compiler can do..
I just finished calculation of a unix date (time in seconds after 1-1-1970), and decreased the routine by 30% AND optimized it extra for speed. Mainly by smart allocating the registers(I used two less than the compiler), and things the computer could not know (60*minutes<3600 seconds, so it fits in a cardinal instead of a longcard). Often you don't realise these things when writing the M2 equivalent.
Another big difference is using rep and loop instructions instead of the spaghetti jmp's the compiler makes out of a FOR or WHILE statement with a
reference to an array in it.
If you compare my code to the compiler's, mine almost seems structured :-(
I seldom use jmp's.
PM> But there's a difference between that theory and practice. The
PM> trouble with assembly language programming is that you have to
PM> spend your time dealing with petty low-level details,
I agree, that's why it's smart to implement only things that NEED the speed in assembler. I also implement Intr and Dos call's in asm, but that's a personal choice. Some routines I use in virtually every program are also optimized,
because I use them so often.
A very small exception to this are those things you can't easy do in M2. Like reversing a BITSET (see msg to granville for details). In assembler one can
use relatively simple shifts. In M2 however you can't do that in the same way. ( o.k. with ODD and << and >>, but it's still different). These things however are most times lowlevel anyway.
PM> "can't see the wood for the trees".
Dutch too? Or is it also an english expression? If you are, you can also reach
me as Fido 2:284/402.18
PM> As a result, you often miss optimisations that the
PM> compiler would have found. Even worse: by concentrating on the
PM> low-level details, you lose track of the broad strategy issues,
PM> so that you can end up implementing bad algorithms.
Not always, assembler also forces you to think about algoritm's and
strategies.
But up till now while programming for a PC, I ALWAYS programmed my routines first in a higher level language (most times : M2) and only started optimizing afterwards, I even have a M2 equivalent of the procedure that reverses a bitset mentioned above. After the programming of the M2 routine, I disassemble it, and try to find a algoritm that only works in assembler, and rearranging the original procedures in a way that allows me to use instructions like rep stosb etc. I can fully recommend this method.
The only exception until now is the pentium detection, because I received it written in assembler, and
PM> For reasons
PM> like this, we often find that programs developed in a language
PM> like Modula-2 out-perform programs developed in assembly language.
Are pure assembly programs still written nowadays? Even modplayers are (partially) in C or Pascal.
PM> on a few occasions, and the result seems to be that you can get
PM> an assembly language program to run about 20% faster than the
PM> equivalent Modula-2 program.
I get 10% speed and size gain only by translating a very small percentage to
assembler (< 5%). The program does some heavy disk-access, so I think the real percentage should even be higher.
PM> (That's a very rough figure, I didn't do precise measurements.)
I did. You can optimize almost every routine. The speedgain is always a few percents for simple procedures, and up to 30% for more complex routines, with a
n optimum for middle size routines.
A lot of exceptions to this rule (larger gains) exist however. The limits between large, middle and small aren't constant either, I define middle size here when the procedure uses
You can also gain a lot of speed by integrating loop structures( repeat,while,for) in your assembly body.
PM> In most situations that level
PM> of improvement doesn't justify the months of extra work you have
PM> to put in to achieve the result.
It's not worth it. However for the example I described above (a program,
exe-size 100k, source >200k which scans a msgbase) I worked 30 hours to optimize it as described. I only started in asm and the topspeed assembler a week before I did this optimalisation. All of the routines I translated are very common
procedures which could be used in many programs. (cursor movement, some simple file stuff not implemented in FIO/FIOR, crc calculation, simple string routines, calculations with dates etc).
The problems you mentioned about C appear to concern the compiler rather then the language.
Marco (M.W.T.J.v.d.Voort@stud.tue.nl or MarcoV@stack.urc.tue.nl)
Technical Details
Message-ID:
<807534257.AA00871@puddle.fidonet.org>Path:
arc1-ca.pugleaf.net!newsfeed.internetmci.com!psgrain!puddle!internetShow Full Headers
Complete Article Headers
From: Marco.van.de.Voort@p18.f402.n284.z2.fidonet.org (Marco van de Voort) Path: arc1-ca.pugleaf.net!newsfeed.internetmci.com!psgrain!puddle!internet Newsgroups: comp.lang.modula2 Subject: TopSpeed and assembler Message-ID: <807534257.AA00871@puddle.fidonet.org> Date: Tue, 01 Aug 1995 14:49:05 -0800 X-FTN-To: Peter Moylan