Thread View: borland.public.delphi.language.basm
32 messages
32 total messages
Started by Bram Bos
Wed, 06 Aug 2008 06:09
WAIT... why?
Author: Bram Bos
Date: Wed, 06 Aug 2008 06:09
Date: Wed, 06 Aug 2008 06:09
29 lines
1756 bytes
1756 bytes
There are a couple of lines in my code that get executed almost 400,000 times per second - so they are good candidates for optimization. Looking at the code generated by Delphi 5 in the CPU window I see this: //lbuffer^ := lbuffer^ + leftvol * l; fld qword ptr [ebp-$28] fmul qword ptr [ebp-$38] fadd qword ptr [edi] fstp qword ptr [edi] wait //inc( lbuffer ); add edi, $08 //rbuffer^ := rbuffer^ + rightvol * l; fld qword ptr [ebp-$30] fmul qword ptr [ebp-$38] mov eax, [ebp-$20] fadd qword ptr [eax] mov eax, [ebp-$20] fstp qword ptr [eax] wait //inc( rbuffer ); add qword ptr [ebp-$20], $08 I notice there is a number of WAIT instructions in there. Why? It seems like a waste of time. But obviously Borland had a good reason to put them there... Also, I guess I can speed up the code above a little bit by using FPU registers and local variables? Thanks for any enlightened insights.
Re: WAIT... why?
Author: Dan Downs
Date: Wed, 06 Aug 2008 11:13
Date: Wed, 06 Aug 2008 11:13
39 lines
2314 bytes
2314 bytes
Bram Bos wrote: > There are a couple of lines in my code that get executed almost 400,000 times per second - so they are good candidates for optimization. > > Looking at the code generated by Delphi 5 in the CPU window I see this: > > //lbuffer^ := lbuffer^ + leftvol * l; > fld qword ptr [ebp-$28] > fmul qword ptr [ebp-$38] > fadd qword ptr [edi] > fstp qword ptr [edi] > wait > //inc( lbuffer ); > add edi, $08 > //rbuffer^ := rbuffer^ + rightvol * l; > fld qword ptr [ebp-$30] > fmul qword ptr [ebp-$38] > mov eax, [ebp-$20] > fadd qword ptr [eax] > mov eax, [ebp-$20] > fstp qword ptr [eax] > wait > //inc( rbuffer ); > add qword ptr [ebp-$20], $08 > > I notice there is a number of WAIT instructions in there. Why? It seems like a waste of time. But obviously Borland had a good reason to put them there... > > Also, I guess I can speed up the code above a little bit by using FPU registers and local variables? > > Thanks for any enlightened insights. > I might be missing something but why is are you multiplying by 1? I would think removing that would speed things up. FPU ASM is way out of my league, but I thought x86 32bit isa used a stack based FPU so I don't know if there are registers per say, you'd have to convert it to SSE. -- DD - Always assume I'm posting without coffee.
Re: WAIT... why?
Author: Bram Bos
Date: Wed, 06 Aug 2008 11:53
Date: Wed, 06 Aug 2008 11:53
30 lines
2175 bytes
2175 bytes
Dan Downs <ddowns@nospam.online-access.com> wrote: >Bram Bos wrote: >> There are a couple of lines in my code that get executed almost 400,000 times per second - so they are good candidates for optimization. >> >> Looking at the code generated by Delphi 5 in the CPU window I see this: >> >> //lbuffer^ := lbuffer^ + leftvol * l; [snip] >> //rbuffer^ := rbuffer^ + rightvol * l; Thanks for having a look at it. >I might be missing something but why is are you multiplying >by 1? I'm actually multiplying by "L", which is a single float variable in this procedure containing a sampled value between -1.0 and +1.0, but apparently the lowercase L looks very similar to a "1" in some fonts ;-) >FPU ASM is way out of my league, but I thought x86 32bit isa >used a stack based FPU so I don't know if there are >registers per say, The x86 FPU uses a stack indeed, but you can still access the 8 items at the top of the stack individually, like registers, as St(0) .. St(7) >you'd have to convert it to SSE. I wish I could - that would have major potential in this situation - however Delphi 5 doesn't support SSE (nor MMX, but there's a handy little byte-code converter available for MMX). Thanks, Bram
Re: WAIT... why?
Author: John Herbster
Date: Wed, 06 Aug 2008 12:22
Date: Wed, 06 Aug 2008 12:22
13 lines
1354 bytes
1354 bytes
"Bram Bos" <buramu@gmail.com> wrote > There are a couple of lines in my code that get executed > almost 400,000 times per second ... > Lbuffer^ := Lbuffer^ + leftvol * L; > inc( Lbuffer ); > Rbuffer^ := Rbuffer^ + rightvol * L; > inc( Rbuffer ); Bram, If you could show us some of the surrounding code, it would help. Rgds, JohnH
Re: WAIT... why?
Author: Bram Bos
Date: Wed, 06 Aug 2008 12:52
Date: Wed, 06 Aug 2008 12:52
54 lines
2517 bytes
2517 bytes
"John Herbster" <herb-sci1_AT_sbcglobal.net> wrote:
>If you could show us some of the surrounding code,
>it would help.
Hi John,
I've simplified the code a bit, but here is the core of the
procedure. Basically it reads a sample from a sound lookup
table, applies volumes to it and stores it in 2 separate
(left/right) buffers.
All samples are "single" values, ranging from -1 to +1...
The two lines I singled out earlier are (according to the profiler) using by far the most CPU time in my entire project, so any performance gain would be useful.
Procedure getSamplesFromWavetable( leftbuf, rightbuf : pointer; numsamples : integer );
var
lbuffer, rbuffer : ^single;
n : integer;
sample, leftvol, rightvol : single;
idx : integer;
begin
Lbuffer := leftbuf;
Rbuffer := rightbuf;
//determine the volume of the left audio channel
leftvol := getLeftVolume();
//determine the volume of the right channel
rightvol := getRightVolume();
for n := 0 to numSamples - 1 do
begin
// get an index into a lookup table containing
// e.g. a sinewave or a sawtooth. This part has already
// been nicely optimized using fixed point arithmatic
idx := getNextIndexIntoWavetable();
// get a sample from the wavetable
sample := oscWavetable[idx];
// now apply volume adjustments to this sample and
// store in separate left/right audio buffers
Lbuffer^ := Lbuffer^ + leftvol * sample;
inc( Lbuffer );
Rbuffer^ := Rbuffer^ + rightvol * sample;
inc( Rbuffer );
end;
end;
Re: WAIT... why?
Author: Jens Gruschel
Date: Wed, 06 Aug 2008 13:26
Date: Wed, 06 Aug 2008 13:26
21 lines
1729 bytes
1729 bytes
> //lbuffer^ := lbuffer^ + leftvol * l; > fld qword ptr [ebp-$28] > fmul qword ptr [ebp-$38] > fadd qword ptr [edi] > fstp qword ptr [edi] > wait > //inc( lbuffer ); > add edi, $08 [...] > I notice there is a number of WAIT instructions in there. Why? It seems like a waste of time. "wait" is necessary to synchronize the FPU with the CPU. When the 80x87 was introduced both were on separate chips working separately and in parallel. The "wait" in the code above makes sure edi is not used by the CPU before the FPU has stored the result to this register. Also see http://www.website.masmforum.com/tutorials/fptute/fpuchap3.htm#fwait Not sure whether wait is still necessary today where CPU and FPU are integrated on a single chip. Does anybody know?
Re: WAIT... why?
Author: Jens Gruschel
Date: Wed, 06 Aug 2008 13:40
Date: Wed, 06 Aug 2008 13:40
6 lines
1345 bytes
1345 bytes
> Not sure whether wait is still necessary today where CPU and FPU are > integrated on a single chip. Does anybody know? According to http://faydoc.tripod.com/cpu/fwait.htm "wait" is also used for the FPU exceptions. Anyway, "sync" probably would have been a better name for it :-)
Re: WAIT... why?
Author: Bram Bos
Date: Wed, 06 Aug 2008 13:47
Date: Wed, 06 Aug 2008 13:47
12 lines
1309 bytes
1309 bytes
Jens Gruschel <nospam@thisurldoesnotexist.com> wrote: >Anyway, "sync" probably would have been a better name for it :-) Ah.. that makes sense.. at least it makes the instruction sound a little bit more useful than "wait" :-) I'll try and figure out whether it's still essential to have critical code littered with waits. I consider the PIII my bottom line CPU, and that one definitely had the FPU integrated into the CPU. Thanks for the info!
Re: WAIT... why?
Author: Jens Gruschel
Date: Wed, 06 Aug 2008 14:11
Date: Wed, 06 Aug 2008 14:11
10 lines
1427 bytes
1427 bytes
> I consider the PIII my > bottom line CPU, and that one definitely had the FPU integrated into the CPU. On the 80286 it was not integrated yet, on the 80486 it was (at least the DX). Not sure about the 80386 (I never had one, I switched from 286 to 486). -- Jens Gruschel http://www.pegtop.net
Re: WAIT... why?
Author: Dan Downs
Date: Wed, 06 Aug 2008 14:14
Date: Wed, 06 Aug 2008 14:14
25 lines
1963 bytes
1963 bytes
Bram Bos wrote: > Dan Downs <ddowns@nospam.online-access.com> wrote: >> Bram Bos wrote: >>> There are a couple of lines in my code that get executed almost 400,000 times per second - so they are good candidates for optimization. >>> >>> Looking at the code generated by Delphi 5 in the CPU window I see this: >>> >>> //lbuffer^ := lbuffer^ + leftvol * l; > [snip] >>> //rbuffer^ := rbuffer^ + rightvol * l; > > Thanks for having a look at it. > >> I might be missing something but why is are you multiplying >> by 1? > > I'm actually multiplying by "L", which is a single float variable in this procedure containing a sampled value between -1.0 and +1.0, but apparently the lowercase L looks very similar to a "1" in some fonts ;-) Doh! Actually 1 and l look almost the same on my system, the one is a pixel shorter and a touch less blurry. Are leftvol and rightvol constants in the loop? DD
Re: WAIT... why?
Author: Dan Downs
Date: Wed, 06 Aug 2008 14:15
Date: Wed, 06 Aug 2008 14:15
6 lines
1279 bytes
1279 bytes
> Are leftvol and rightvol constants in the loop? I should have looked at the other posts first, never mind. -- DD - Always assume I'm posting without coffee.
Re: WAIT... why?
Author: Dan Downs
Date: Wed, 06 Aug 2008 14:17
Date: Wed, 06 Aug 2008 14:17
15 lines
1488 bytes
1488 bytes
Jens Gruschel wrote: >> I consider the PIII my >> bottom line CPU, and that one definitely had the FPU integrated into >> the CPU. > > On the 80286 it was not integrated yet, on the 80486 it was (at least > the DX). Not sure about the 80386 (I never had one, I switched from 286 > to 486). > 386 was still external, I had a math co-processor. -- DD - Always assume I'm posting without coffee.
Re: WAIT... why?
Author: Dan Downs
Date: Wed, 06 Aug 2008 14:27
Date: Wed, 06 Aug 2008 14:27
15 lines
1637 bytes
1637 bytes
Depending on how getNextIndexIntoWavetable() works it looks like you could split the loop into two threads. Left & right channel threads and wait for both before returning, that mixed with any possible fpu improvements the others come up with could add up to quite a bit. It would depend on numsamples being large enough to warrant using threads though. If its more of a real time problem then some sort of threaded pipeline/queuing structure might be better. I've been following http://17slon.com/blogs/gabr/blogger.html with much interest lately. -- DD - Always assume I'm posting without coffee.
Re: WAIT... why?
Author: Bob Gonder
Date: Wed, 06 Aug 2008 14:58
Date: Wed, 06 Aug 2008 14:58
25 lines
1663 bytes
1663 bytes
Bram Bos wrote:
> // now apply volume adjustments to this sample and
> // store in separate left/right audio buffers
> Lbuffer^ := Lbuffer^ + leftvol * sample;
> inc( Lbuffer );
> Rbuffer^ := Rbuffer^ + rightvol * sample;
> inc( Rbuffer );
Change to
Lbuffer^ := Lbuffer^ + leftvol * sample;
Rbuffer^ := Rbuffer^ + rightvol * sample;
inc( Lbuffer );
inc( Rbuffer );
Will eliminate the first wait.
But I don't think it will speed up very much.
As to Why the Wait...If you didn't wait,
edi would be changed to edi+8 before
the fstp[edi] got around to executing.
This might be a good candidate for threadng.
One thread for each channel on a multi-cpu
chip should be twice as fast.
Re: WAIT... why?
Author: Dennis Passmore
Date: Wed, 06 Aug 2008 17:24
Date: Wed, 06 Aug 2008 17:24
1 lines
916 bytes
916 bytes
check your email
Re: WAIT... why?
Author: Carl Caulkett
Date: Wed, 06 Aug 2008 17:55
Date: Wed, 06 Aug 2008 17:55
14 lines
1054 bytes
1054 bytes
Bram Bos wrote: > > There are a couple of lines in my code that get executed almost > 400,000 times per second - so they are good candidates for > optimization. Hi, are you the Bram Bos of Hammerhead and Tuareg fame? Although I'm more of an FL Studio man these days, I had fun with Hammerhead when it first came out. -- Cheers, Carl
Re: WAIT... why?
Author: Derek Jones
Date: Wed, 06 Aug 2008 18:01
Date: Wed, 06 Aug 2008 18:01
14 lines
1544 bytes
1544 bytes
"Jens Gruschel" <nospam@thisurldoesnotexist.com> wrote in message news:4899a627> > > Not sure whether wait is still necessary today where CPU and FPU are > integrated on a single chip. Does anybody know? Not according to the Intel IA-32 docs. It's only use these days is to syncronize floating point exceptions. And if you look at where the Delphi compiler places them it is after each source line, so that if an exception is generated, it is handled and flagged for the correct line. If you code by hand and omit the waits, you will often get the exception some instructions later than where it actualy occured.
Re: WAIT... why?
Author: Derek Jones
Date: Wed, 06 Aug 2008 18:05
Date: Wed, 06 Aug 2008 18:05
15 lines
1553 bytes
1553 bytes
"Bob Gonder" <none@nowhere.invalid> wrote in message news:9aej94dup0sk6ro0ir4kcmc0lfkbup9ffg@4ax.com... > > As to Why the Wait...If you didn't wait, > edi would be changed to edi+8 before > the fstp[edi] got around to executing. These days it's only use is to sync floating point exceptions. If you look at where they are placed by the compiler, it is at the end of each source line, so the debugger can flag the correct source line should an exception occur. The Intel IA32 docs state that it is for exception syncronization, nothing else.
Re: WAIT... why?
Author: Bram Bos
Date: Wed, 06 Aug 2008 18:44
Date: Wed, 06 Aug 2008 18:44
29 lines
1831 bytes
1831 bytes
"Carl Caulkett" <carlca@dircon.co.uk> wrote: >Bram Bos wrote: > >> >> There are a couple of lines in my code that get executed almost >> 400,000 times per second - so they are good candidates for >> optimization. > >Hi, are you the Bram Bos of Hammerhead and Tuareg fame? Although I'm >more of an FL Studio man these days, I had fun with Hammerhead when it >first came out. Hi Carl, Yes.. that's me. Funny you remember my name. I made Hammerhead over 10 years ago! Incidentally that was my first real Delphi application ;-) I'm currently working on a freeware all-in-one music application for tiny netbooks, like the Asus EEE PC. These typically have small screens and slow, last-gen CPUs so that's why I need to optimize my synth and mix code as much as possible (my own EEE PC has an underclocked Celeron M @ 630MHz so that explains why I'm interested in assembler all of a sudden). Cheers, Bram
Re: WAIT... why?
Author: Jens Gruschel
Date: Wed, 06 Aug 2008 21:02
Date: Wed, 06 Aug 2008 21:02
15 lines
1479 bytes
1479 bytes
> Yes.. that's me. Funny you remember my name. > I made Hammerhead over 10 years ago! Incidentally that was > my first real Delphi application ;-) Hammerhead was great, one of the first applications I had when I switched from DOS to Windows. Thanks for that! > I'm currently working on a freeware all-in-one music > application for tiny netbooks, like the Asus EEE PC. Sounds interesting. Let us know when it's done :-) -- Jens Gruschel http://www.pegtop.net
Re: WAIT... why?
Author: Dennis Christensen
Date: Thu, 07 Aug 2008 06:41
Date: Thu, 07 Aug 2008 06:41
41 lines
2176 bytes
2176 bytes
Hi > I notice there is a number of WAIT instructions in there. Why? It seems > like a waste of time. But obviously Borland had a good reason to put them > there... WAIT is not a sleep. > Also, I guess I can speed up the code above a little bit by using FPU > registers and local variables? The WAIT instruction = FWAIT takes 0 clock cycles to execute on modern processors. Do not worry about them. > Thanks for any enlightened insights. http://download.intel.com/design/pentium/MANUALS/24319101.PDF page 485 Description Causes the processor to check for and handle pending, unmasked, floating-point exceptions before proceeding. (FWAIT is an alternate mnemonic for the WAIT). This instruction is useful for synchronizing exceptions in critical sections of code. Coding a WAIT instruction after a floating-point instruction insures that any unmasked floating-point exceptions the instruction may raise are handled before the processor can modify the instruction's results. See the section titled "Floating-Point Exception Synchronization" in Chapter 7 of the Intel Architecture Software Developer's Manual, Volume 1, for more Regards Dennis
Re: WAIT... why?
Author: Dennis Christensen
Date: Thu, 07 Aug 2008 06:46
Date: Thu, 07 Aug 2008 06:46
13 lines
1313 bytes
1313 bytes
Hi Derek I agree I have often tried removing FWAIT instructions in BASM code and I have never been able to measure any difference in speed. They are needed after FP instructions that can raise exceptions if one wants the exception at the rigth line. If one does not care then having one at the end of a function is enough. Regards Dennis
Re: WAIT... why?
Author: Dennis Christensen
Date: Thu, 07 Aug 2008 06:47
Date: Thu, 07 Aug 2008 06:47
6 lines
1084 bytes
1084 bytes
Hi Why care about anything older than P4 these days? Regards Dennis
Re: WAIT... why?
Author: David J Taylor
Date: Thu, 07 Aug 2008 06:57
Date: Thu, 07 Aug 2008 06:57
13 lines
1550 bytes
1550 bytes
Dennis Christensen wrote: > Hi > > Why care about anything older than P4 these days? > > Regards > Dennis I have at least two production real-time data capture systems still running Pentium III with Windows 2000, and no intention to replace them any time soon. David
Re: WAIT... why?
Author: Bram Bos
Date: Thu, 07 Aug 2008 06:58
Date: Thu, 07 Aug 2008 06:58
9 lines
1272 bytes
1272 bytes
Jens Gruschel <nospam@thisurldoesnotexist.com> wrote: >> I'm currently working on a freeware all-in-one music >> application for tiny netbooks, like the Asus EEE PC. > >Sounds interesting. Let us know when it's done :-) I will and I definitely need to credit the people in this group in my documentation, because I've already learned an awful lot just reading through the archives of this newsgroup.
Re: WAIT... why?
Author: Bram Bos
Date: Thu, 07 Aug 2008 07:02
Date: Thu, 07 Aug 2008 07:02
9 lines
1589 bytes
1589 bytes
"Dennis Christensen" <dkc@GateHouse.dk> wrote: >Hi > >Why care about anything older than P4 these days? For this particular project (as I explained further down the thread) I'm writing specifically for ultraportable netbooks like the Asus EEE PC. The basic model uses an old Celeron M (Dothan-900) running underclocked at 630MHz. So it's basically a slowed down Pentium III with some P4 sauce. These are still far from being obsolete.
Re: WAIT... why?
Author: thaddy
Date: Thu, 07 Aug 2008 08:12
Date: Thu, 07 Aug 2008 08:12
8 lines
1223 bytes
1223 bytes
De compiler has no way of knowing you are doing audio and that it can safely ignore de fpu state in most cases. You can set the FPU state to ignore floating point exceptions. In that case the wait will take no cycles. btw: I have some old BASM code that does the same as you do here: http://thaddy.co.uk/tdkdsplib.zip Maybe you can use it.
Re: WAIT... why?
Author: Bram Bos
Date: Thu, 07 Aug 2008 08:20
Date: Thu, 07 Aug 2008 08:20
13 lines
1416 bytes
1416 bytes
"thaddy" <thaddy@thaddy.com> wrote: > >De compiler has no way of knowing you are doing audio and that it can safely ignore de fpu state in most cases. >You can set the FPU state to ignore floating point exceptions. In that case the wait will take no cycles. > >btw: I have some old BASM code that does the same as you do here: >http://thaddy.co.uk/tdkdsplib.zip > >Maybe you can use it. Thanks.. it looks like I should give the AdjustVolume32f procedure a good closer look. Very helpful!
Re: WAIT... why?
Author: Q Correll
Date: Thu, 07 Aug 2008 16:42
Date: Thu, 07 Aug 2008 16:42
14 lines
1184 bytes
1184 bytes
Dennis,
| The WAIT instruction = FWAIT takes 0 clock cycles to execute on modern
processors. Do not worry about them.
How about the instruction decode cycle? How does the cpu know it's a WAIT
until the instruction is read?
--
Q
08/07/2008 09:41:26
XanaNews Version 1.18.1.11 [Leonel's & Pieter's & Q's Mods]
Re: WAIT... why?
Author: Bob Gonder
Date: Thu, 07 Aug 2008 18:02
Date: Thu, 07 Aug 2008 18:02
12 lines
1225 bytes
1225 bytes
Dennis Christensen wrote: >The WAIT instruction = FWAIT takes 0 clock cycles to execute on modern >processors. Do not worry about them. Hmmm.. My 3GHz Quad runs (using GetTickCount() ) 10 million 16-nop loop in 31 10 million 16-wait loop in 62 My 2GHz Celeron laptop in 50/90 So it looks like it takes twice as long as the 0-cycle nop :->
Re: WAIT... why?
Author: Hubert Seidel
Date: Sat, 09 Aug 2008 18:14
Date: Sat, 09 Aug 2008 18:14
28 lines
1902 bytes
1902 bytes
Hello Bram, "Bram Bos" <buramu@gmail.com> schrieb im Newsbeitrag news:4899402f$1@newsgroups.borland.com... > > There are a couple of lines in my code that get executed almost 400,000 times per second - so they are good candidates for optimization. > Looking at the code generated by Delphi 5 in the CPU window I see this: .. > Also, I guess I can speed up the code above a little bit by using FPU registers and local variables? If you have an example for us that i can compile and run, then i can try to supporting. We had success "I need the fastest routine" news:486e9cec@newsgroups.borland.com e.g. e small projekt with a procedure than fills the array (sin/cos) and a procedure with the main-function. (I have Delphi 5 too) mfg. Herby P.S: Sorry, my english,...i hope yor understand me :-) -- http://www.hubert-seidel.de
Re: WAIT... why?
Author: Hubert Seidel
Date: Sat, 09 Aug 2008 19:53
Date: Sat, 09 Aug 2008 19:53
59 lines
2807 bytes
2807 bytes
Hello Bram, "Bram Bos" <buramu@gmail.com> schrieb im Newsbeitrag news:48999e7b$1@newsgroups.borland.com... ... > Procedure getSamplesFromWavetable( leftbuf, rightbuf : pointer; numsamples : integer ); > var > lbuffer, rbuffer : ^single; > n : integer; > sample, leftvol, rightvol : single; > idx : integer; > begin > > Lbuffer := leftbuf; > Rbuffer := rightbuf; > > //determine the volume of the left audio channel > leftvol := getLeftVolume(); > //determine the volume of the right channel > rightvol := getRightVolume(); > > for n := 0 to numSamples - 1 do > begin > > // get an index into a lookup table containing > // e.g. a sinewave or a sawtooth. This part has already > // been nicely optimized using fixed point arithmatic ### > idx := getNextIndexIntoWavetable(); ### What do this function? It is possible that this is the bottleneck, i don't know without to see the code.. > > // get a sample from the wavetable > sample := oscWavetable[idx]; ### I think move the code from getNextIndexIntoWavetable to here and combine with sample := with some transpositions could incrase the speed. > > // now apply volume adjustments to this sample and > // store in separate left/right audio buffers > Lbuffer^ := Lbuffer^ + leftvol * sample; > inc( Lbuffer ); > Rbuffer^ := Rbuffer^ + rightvol * sample; > inc( Rbuffer ); With external function-calls, you (or i) can't be sure what to do the FPU. I have some ideas to optimize the code, if there are not surprises in external call. mfg. Herby -- http://www.hubert-seidel.de
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads