Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.forth > #41372 > unrolled thread
| Started by | Mark Wills <markwills1970@gmail.com> |
|---|---|
| First post | 2015-08-18 08:44 -0700 |
| Last post | 2015-08-19 02:58 +0200 |
| Articles | 20 on this page of 30 — 12 participants |
Back to article view | Back to comp.lang.forth
CMOVE/CMOVE> Mark Wills <markwills1970@gmail.com> - 2015-08-18 08:44 -0700
Re: CMOVE/CMOVE> anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2015-08-18 16:05 +0000
Re: CMOVE/CMOVE> november.nihal@gmail.com - 2015-08-18 09:34 -0700
Re: CMOVE/CMOVE> anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2015-08-18 16:41 +0000
Re: CMOVE/CMOVE> Mark Wills <markwills1970@gmail.com> - 2015-08-18 09:59 -0700
Re: CMOVE/CMOVE> Michael Barry <barrym95838@yahoo.com> - 2015-08-18 10:10 -0700
Re: CMOVE/CMOVE> hughaguilar96@gmail.com - 2015-08-18 10:41 -0700
Re: CMOVE/CMOVE> "Alex McDonald" <blog@rivadpm.com> - 2015-08-18 23:55 +0100
Re: CMOVE/CMOVE> anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2015-08-19 08:40 +0000
Re: CMOVE/CMOVE> "Alex McDonald" <blog@rivadpm.com> - 2015-08-19 12:15 +0100
Re: CMOVE/CMOVE> Mark Wills <markwills1970@gmail.com> - 2015-08-18 11:35 -0700
Re: CMOVE/CMOVE> Mark Wills <markwills1970@gmail.com> - 2015-08-18 11:36 -0700
Re: CMOVE/CMOVE> "HAA" <someone@microsoft.com> - 2015-08-20 04:39 +1000
Re: CMOVE/CMOVE> "Elizabeth D. Rather" <erather@forth.com> - 2015-08-19 09:15 -1000
Re: CMOVE/CMOVE> "HAA" <someone@microsoft.com> - 2015-08-28 22:39 +1000
Re: CMOVE/CMOVE> Coos Haak <chforth@hccnet.nl> - 2015-08-28 15:06 +0200
Re: CMOVE/CMOVE> "HAA" <someone@microsoft.com> - 2015-08-29 17:15 +1000
Re: CMOVE/CMOVE> Coos Haak <chforth@hccnet.nl> - 2015-08-29 13:24 +0200
Re: CMOVE/CMOVE> "HAA" <someone@microsoft.com> - 2015-08-31 11:38 +1000
Re: CMOVE/CMOVE> "Elizabeth D. Rather" <erather@forth.com> - 2015-08-29 07:59 -1000
Re: CMOVE/CMOVE> "HAA" <someone@microsoft.com> - 2015-08-30 13:00 +1000
Re: CMOVE/CMOVE> Mark Wills <markwills1970@gmail.com> - 2015-08-28 07:33 -0700
Re: CMOVE/CMOVE> Mark Wills <markwills1970@gmail.com> - 2015-08-28 07:36 -0700
Re: CMOVE/CMOVE> "HAA" <someone@microsoft.com> - 2015-08-29 02:23 +1000
Re: CMOVE/CMOVE> mhx@iae.nl - 2015-08-28 11:41 -0700
Re: CMOVE/CMOVE> "HAA" <someone@microsoft.com> - 2015-08-29 17:30 +1000
Re: CMOVE/CMOVE> anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2015-08-19 08:04 +0000
Re: CMOVE/CMOVE> "Rod Pemberton" <boo@fasdfrewar.cdm> - 2015-08-19 02:48 -0400
Re: CMOVE/CMOVE> Mark Wills <markwills1970@gmail.com> - 2015-08-19 00:49 -0700
Re: CMOVE/CMOVE> Bernd Paysan <bernd.paysan@gmx.de> - 2015-08-19 02:58 +0200
Page 1 of 2 [1] 2 Next page →
| From | Mark Wills <markwills1970@gmail.com> |
|---|---|
| Date | 2015-08-18 08:44 -0700 |
| Subject | CMOVE/CMOVE> |
| Message-ID | <62627f57-1e63-4156-844a-db5708923aaf@googlegroups.com> |
I'm aware of the word MOVE which will choose to perform either a CMOVE or CMOVE> depending on overlap and direction. My system doesn't have MOVE though I'd like to implement it. Does anyone have any nice concise logic for checking the parameters and calling either CMOVE or CMOVE> accordingly? Many thanks Mark
[toc] | [next] | [standalone]
| From | anton@mips.complang.tuwien.ac.at (Anton Ertl) |
|---|---|
| Date | 2015-08-18 16:05 +0000 |
| Message-ID | <2015Aug18.180551@mips.complang.tuwien.ac.at> |
| In reply to | #41372 |
Mark Wills <markwills1970@gmail.com> writes:
>I'm aware of the word MOVE which will choose to perform either a CMOVE or CMOVE> depending on overlap and direction. My system doesn't have MOVE though I'd like to implement it.
>
>Does anyone have any nice concise logic for checking the parameters and calling either CMOVE or CMOVE> accordingly?
: move ( from to count -- )
>r 2dup u< if
r> cmove>
else
r> cmove
then ;
Better branch prediction accuracy:
: move ( from to count -- )
>r 2dup dup r@ + within if
r> cmove
else
r> cmove>
then ;
Both not tested.
- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard: http://www.forth200x.org/forth200x.html
EuroForth 2015: http://www.mpeforth.com/euroforth2015/euroforth2015.htm
[toc] | [prev] | [next] | [standalone]
| From | november.nihal@gmail.com |
|---|---|
| Date | 2015-08-18 09:34 -0700 |
| Message-ID | <ba32a33b-cf92-46fa-9162-77ca74c8bec4@googlegroups.com> |
| In reply to | #41375 |
for the second example ; shouldn't that be : >r 2dup over r@ + within if ( from + count ) ? NN
[toc] | [prev] | [next] | [standalone]
| From | anton@mips.complang.tuwien.ac.at (Anton Ertl) |
|---|---|
| Date | 2015-08-18 16:41 +0000 |
| Message-ID | <2015Aug18.184133@mips.complang.tuwien.ac.at> |
| In reply to | #41376 |
november.nihal@gmail.com writes:
>
>for the second example ;
>
>shouldn't that be : >r 2dup over r@ + within if ( from + count ) ?
My idea was to test whether FROM is within [TO, TO+COUNT), so I think
my version is right. Other variations are also possible, of course.
- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard: http://www.forth200x.org/forth200x.html
EuroForth 2015: http://www.mpeforth.com/euroforth2015/euroforth2015.htm
[toc] | [prev] | [next] | [standalone]
| From | Mark Wills <markwills1970@gmail.com> |
|---|---|
| Date | 2015-08-18 09:59 -0700 |
| Message-ID | <c3289222-a562-44db-a30a-1f8d58d0fc6b@googlegroups.com> |
| In reply to | #41375 |
On Tuesday, 18 August 2015 17:16:28 UTC+1, Anton Ertl wrote: > Mark Wills <markwills1970@gmail.com> writes: > >I'm aware of the word MOVE which will choose to perform either a CMOVE or CMOVE> depending on overlap and direction. My system doesn't have MOVE though I'd like to implement it. > > > >Does anyone have any nice concise logic for checking the parameters and calling either CMOVE or CMOVE> accordingly? > > : move ( from to count -- ) > >r 2dup u< if > r> cmove> > else > r> cmove > then ; > > Better branch prediction accuracy: > > : move ( from to count -- ) > >r 2dup dup r@ + within if > r> cmove > else > r> cmove> > then ; > > Both not tested. > > - anton > -- > M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html > comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html > New standard: http://www.forth200x.org/forth200x.html > EuroForth 2015: http://www.mpeforth.com/euroforth2015/euroforth2015.htm That's nice code, thank you. Mine also included WITHIN but your first example is neater IMO. I just tested it quickly and it seems to work fine. Thanks. Mark
[toc] | [prev] | [next] | [standalone]
| From | Michael Barry <barrym95838@yahoo.com> |
|---|---|
| Date | 2015-08-18 10:10 -0700 |
| Message-ID | <cc2c79a3-48ce-400e-b3b6-4474c9c47917@googlegroups.com> |
| In reply to | #41378 |
On Tuesday, August 18, 2015 at 9:59:02 AM UTC-7, Mark Wills wrote: > > > : move ( from to count -- ) > > >r 2dup u< if > > r> cmove> > > else > > r> cmove > > then ; > > > > Better branch prediction accuracy: > > > > : move ( from to count -- ) > > >r 2dup dup r@ + within if > > r> cmove > > else > > r> cmove> > > then ; > > > > Both not tested. > > > > - anton > > -- > > > > That's nice code, thank you. Mine also included WITHIN but your first > example is neater IMO. I just tested it quickly and it seems to work fine. > > Thanks. > > Mark Isn't it true that the decision can be made based simply on whether source start is less than destination start, regardless of count? Mine does that, but CMOVE> and CMOVE have equivalent performance, which might mot always be the case. [code] ;----------- 65m32: smart move -------- ; Move memory up/down (1 W to 4 GW) ; x = source start address ; y = destination start address ; b = number of words to move ; (4 GW are moved if b == 0 !!) ; :88020000 move: cpy #,x :42420000 mvdown: lda [cc],x+ :a2440000 sta [cc],y+ :8c49fffd dbn [cc]mvdown,b :5e4c0000 rts [cc] :e4080000 adx #,b :e8080000 ady #,b :43020000 moveup: lda ,-x :a3040000 sta ,-y :8c09fffd dbn moveup,b :5e0c0000 rts [/code] Mike B.
[toc] | [prev] | [next] | [standalone]
| From | hughaguilar96@gmail.com |
|---|---|
| Date | 2015-08-18 10:41 -0700 |
| Message-ID | <70231de3-da52-405a-a20d-a578e9783f12@googlegroups.com> |
| In reply to | #41379 |
On Tuesday, August 18, 2015 at 10:10:22 AM UTC-7, Michael Barry wrote: > On Tuesday, August 18, 2015 at 9:59:02 AM UTC-7, Mark Wills wrote: > > > > > : move ( from to count -- ) > > > >r 2dup u< if > > > r> cmove> > > > else > > > r> cmove > > > then ; > > > > > > Better branch prediction accuracy: > > > > > > : move ( from to count -- ) > > > >r 2dup dup r@ + within if > > > r> cmove > > > else > > > r> cmove> > > > then ; > > > > > > Both not tested. > > > > > > - anton > > > -- > > > > > > > That's nice code, thank you. Mine also included WITHIN but your first > > example is neater IMO. I just tested it quickly and it seems to work fine. > > > > Thanks. > > > > Mark > > Isn't it true that the decision can be made based simply on whether source start is less than destination start, regardless of count? Mine does that, but CMOVE> and CMOVE have equivalent performance, which might mot always be the case. Yes, it is only necessary to compare the start addresses. Checking the count to determine if CMOVE> is strictly necessary presumes that CMOVE> should be avoided as much as possible. I don't really know why there would be any difference in speed on any processor though. There is a slight overhead with CMOVE> in that you have to add the counts to the start-addresses to obtain the limit-addresses, but that is done only once and should be over-shadowed by the time needed to do all the moves. It would be a good idea to have a MOVE that is only for structs whose size is a cell-multiple (this is always true in the novice-package because FIELD cell-aligns the fields in a struct). It would also be a good idea to have an EXCHANGE like I do in the novice-package (but it is very slow when written in Forth rather than assembly-language). Note that mine assumes that the struct size is a cell-multiple. Anyway --- none of these good ideas will be in Forth-200x --- at least, not unless Leon Wagner says so. > [code] > > ;----------- 65m32: smart move -------- > ; Move memory up/down (1 W to 4 GW) > ; x = source start address > ; y = destination start address > ; b = number of words to move > ; (4 GW are moved if b == 0 !!) > ; > :88020000 move: cpy #,x > :42420000 mvdown: lda [cc],x+ > :a2440000 sta [cc],y+ > :8c49fffd dbn [cc]mvdown,b > :5e4c0000 rts [cc] > :e4080000 adx #,b > :e8080000 ady #,b > :43020000 moveup: lda ,-x > :a3040000 sta ,-y > :8c09fffd dbn moveup,b > :5e0c0000 rts > [/code] > > Mike B. Oh, I just noticed that your code does move cells. I think you mentioned that you don't have byte-addressing. Why don't you publish a document describing your 65m32 similar to my document describing the FMITE processor? Nobody knows what any of those instructions do. BTW: does the 'm' in 65m32 stand for "Michael"?
[toc] | [prev] | [next] | [standalone]
| From | "Alex McDonald" <blog@rivadpm.com> |
|---|---|
| Date | 2015-08-18 23:55 +0100 |
| Message-ID | <mr0d1a$ke7$1@dont-email.me> |
| In reply to | #41380 |
on 18/08/2015 18:41:19, wrote: > > On Tuesday, August 18, 2015 at 10:10:22 AM UTC-7, Michael Barry wrote: >> >> Isn't it true that the decision can be made based simply on whether sourc > e start is less than destination start, regardless of count? Mine does > tha t, but CMOVE> and CMOVE have equivalent performance, which might > mot always be the case. > > Yes, it is only necessary to compare the start addresses. No, because if there's an overlap then there may be advantages in using larger than CHAR sized moves. When there is an overlap, CMOVE> should always do a character by character move (for instance, on the x86 REP MOVS BYTE); otherwise much larger units can be CMOVE>d if there is no overlap (REP MOVS DWORD or QWORD or MOVDQU thru XMM registers, etc). The difference in performance can be considerable.
[toc] | [prev] | [next] | [standalone]
| From | anton@mips.complang.tuwien.ac.at (Anton Ertl) |
|---|---|
| Date | 2015-08-19 08:40 +0000 |
| Message-ID | <2015Aug19.104049@mips.complang.tuwien.ac.at> |
| In reply to | #41385 |
"Alex McDonald" <blog@rivadpm.com> writes:
>on 18/08/2015 18:41:19, wrote:
>> > On Tuesday, August 18, 2015 at 10:10:22 AM UTC-7, Michael Barry wrote:
>
>>>
>>> Isn't it true that the decision can be made based simply on whether sourc
>> e start is less than destination start, regardless of count? Mine does
>> tha t, but CMOVE> and CMOVE have equivalent performance, which might
>> mot always be the case.
>>
>> Yes, it is only necessary to compare the start addresses.
>
>No, because if there's an overlap then there may be advantages in using
>larger than CHAR sized moves. When there is an overlap, CMOVE> should
>always do a character by character move (for instance, on the x86 REP
>MOVS BYTE); otherwise much larger units can be CMOVE>d if there is no
>overlap (REP MOVS DWORD or QWORD or MOVDQU thru XMM registers, etc). The
>difference in performance can be considerable.
If you implement MOVE, you can use larger granularity for either
direction (of course, you need to take care of the remainder at the
start and/or end). I would hope that on an IA-32/AMD64 CPU the CPU
does that for you if you use REP MOVSB and the parameters are
appropriate. Unfortunately, it seems that doing it in software is
faster, at least for microbenchmarks, and this has lead to glibc's
memmove() having 11KB of code. This is likely to be slower in
applications due to I-cache misses, but as long as it produces good
microbenchmark results...
Even for CMOVE or CMOVE> you can usually use a larger granularity even
for the overlap case; the granularity for CMOVE must just be at most
TO-FROM for CMOVE and FROM-TO for CMOVE>.
- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard: http://www.forth200x.org/forth200x.html
EuroForth 2015: http://www.mpeforth.com/euroforth2015/euroforth2015.htm
[toc] | [prev] | [next] | [standalone]
| From | "Alex McDonald" <blog@rivadpm.com> |
|---|---|
| Date | 2015-08-19 12:15 +0100 |
| Message-ID | <mr1oe9$m8m$1@dont-email.me> |
| In reply to | #41396 |
on 19/08/2015 09:40:45, wrote: > "Alex McDonald" <blog@rivadpm.com> writes: >>on 18/08/2015 18:41:19, wrote: >>> > On Tuesday, August 18, 2015 at 10:10:22 AM UTC-7, Michael Barry wrote: >> >>>> >>>> Isn't it true that the decision can be made based simply on whether sourc >>> e start is less than destination start, regardless of count? Mine does >>> tha t, but CMOVE> and CMOVE have equivalent performance, which might >>> mot always be the case. >>> >>> Yes, it is only necessary to compare the start addresses. >> >>No, because if there's an overlap then there may be advantages in using s/there's an overlap/there's not an overlap/ but you got my drift. >>larger than CHAR sized moves. When there is an overlap, CMOVE> should >>always do a character by character move (for instance, on the x86 REP >>MOVS BYTE); otherwise much larger units can be CMOVE>d if there is no >>overlap (REP MOVS DWORD or QWORD or MOVDQU thru XMM registers, etc). The >>difference in performance can be considerable. > > If you implement MOVE, you can use larger granularity for either > direction (of course, you need to take care of the remainder at the > start and/or end). I would hope that on an IA-32/AMD64 CPU the CPU > does that for you if you use REP MOVSB and the parameters are > appropriate. Unfortunately, it seems that doing it in software is > faster, at least for microbenchmarks, and this has lead to glibc's > memmove() having 11KB of code. This is likely to be slower in > applications due to I-cache misses, but as long as it produces good > microbenchmark results... On further reading, it appears that (for instance, the Intel Haswell) REP MOVS BYTE is optimised iif both source and dest are aligned to 32 bytes. http://www.agner.org/optimize/microarchitecture.pdf pg 142 where it recommends 256 bit registers otherwise. The net is full of contrarian advice and equally varied code. This is BSD's memmove() http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/lib/libkern/arch/amd64/memmove.S?rev=1.5&content-type=text/plain It's much shorter and the very paragon of simplicity compared to the glibc version. My CMOVE CMOVE> use MOVS BYTE; MOVE uses MOVS DWORD for the bulk word aligned and MOVS BYTE for the remaining top and tail. I wrote a bulk copy based on MOVDQU. I haven't benchmarked it properly, but it was marginally but measurably faster than MOVE for large blocks. > > Even for CMOVE or CMOVE> you can usually use a larger granularity even > for the overlap case; the granularity for CMOVE must just be at most > TO-FROM for CMOVE and FROM-TO for CMOVE>. Point taken; the overlap still needs checked to do so. > > - anton
[toc] | [prev] | [next] | [standalone]
| From | Mark Wills <markwills1970@gmail.com> |
|---|---|
| Date | 2015-08-18 11:35 -0700 |
| Message-ID | <c4beff92-d7da-4b6c-a37a-b40478fd914f@googlegroups.com> |
| In reply to | #41379 |
On Tuesday, 18 August 2015 18:10:22 UTC+1, Michael Barry wrote:
> On Tuesday, August 18, 2015 at 9:59:02 AM UTC-7, Mark Wills wrote:
> >
> > > : move ( from to count -- )
> > > >r 2dup u< if
> > > r> cmove>
> > > else
> > > r> cmove
> > > then ;
> > >
> > > Better branch prediction accuracy:
> > >
> > > : move ( from to count -- )
> > > >r 2dup dup r@ + within if
> > > r> cmove
> > > else
> > > r> cmove>
> > > then ;
> > >
> > > Both not tested.
> > >
> > > - anton
> > > --
> > >
> >
> > That's nice code, thank you. Mine also included WITHIN but your first
> > example is neater IMO. I just tested it quickly and it seems to work fine.
> >
> > Thanks.
> >
> > Mark
>
> Isn't it true that the decision can be made based simply on whether source start is less than destination start, regardless of count? Mine does that, but CMOVE> and CMOVE have equivalent performance, which might mot always be the case.
>
> [code]
>
> ;----------- 65m32: smart move --------
> ; Move memory up/down (1 W to 4 GW)
> ; x = source start address
> ; y = destination start address
> ; b = number of words to move
> ; (4 GW are moved if b == 0 !!)
> ;
> :88020000 move: cpy #,x
> :42420000 mvdown: lda [cc],x+
> :a2440000 sta [cc],y+
> :8c49fffd dbn [cc]mvdown,b
> :5e4c0000 rts [cc]
> :e4080000 adx #,b
> :e8080000 ady #,b
> :43020000 moveup: lda ,-x
> :a3040000 sta ,-y
> :8c09fffd dbn moveup,b
> :5e0c0000 rts
> [/code]
>
> Mike B.
I think so, yes.
I just knocked this up to move blocks around. It's for my hobby Forth
system running on antiquated (>30 years old) hardware. Think 5.25"
floppies and you're in the ball park.
It uses locals. From some quick experiments, locals on a dumb (non-
optimising) ITC makes things faster. The reason? All the stack juggling
goes away. Those ROTs DUPs SWAPs etc are burning up time just getting
the stack arranged. Locals on a dumb system takes that away. The
argument doesn't hold on modern optimising systems.
Anyway, it's moot... The disk I/O is millions of times slower than
the code! But locals sure makes it easy... Like falling of a log.
Ignore FLUSH? It just checks the block buffers and one or more is
not flushed (dirty?) it offers the choice to do a flush first.
: movblk ( src dest cnt -- )
locals{ src dest cnt cpydir }
set cnt set dest set src
src dest < if
cnt 1- +set src
cnt 1- +set dest
-1 set cpydir
else
1 set cpydir
then flush?
cnt 0 do
2 spaces src . ." to " dest .
src block drop 0 dest setblk 0 dirty flush
cpydir +set src
cpydir +set dest
loop ;
[toc] | [prev] | [next] | [standalone]
| From | Mark Wills <markwills1970@gmail.com> |
|---|---|
| Date | 2015-08-18 11:36 -0700 |
| Message-ID | <277a4458-52c2-4bbc-a068-f862ceaf4358@googlegroups.com> |
| In reply to | #41381 |
On Tuesday, 18 August 2015 19:35:58 UTC+1, Mark Wills wrote:
> On Tuesday, 18 August 2015 18:10:22 UTC+1, Michael Barry wrote:
> > On Tuesday, August 18, 2015 at 9:59:02 AM UTC-7, Mark Wills wrote:
> > >
> > > > : move ( from to count -- )
> > > > >r 2dup u< if
> > > > r> cmove>
> > > > else
> > > > r> cmove
> > > > then ;
> > > >
> > > > Better branch prediction accuracy:
> > > >
> > > > : move ( from to count -- )
> > > > >r 2dup dup r@ + within if
> > > > r> cmove
> > > > else
> > > > r> cmove>
> > > > then ;
> > > >
> > > > Both not tested.
> > > >
> > > > - anton
> > > > --
> > > >
> > >
> > > That's nice code, thank you. Mine also included WITHIN but your first
> > > example is neater IMO. I just tested it quickly and it seems to work fine.
> > >
> > > Thanks.
> > >
> > > Mark
> >
> > Isn't it true that the decision can be made based simply on whether source start is less than destination start, regardless of count? Mine does that, but CMOVE> and CMOVE have equivalent performance, which might mot always be the case.
> >
> > [code]
> >
> > ;----------- 65m32: smart move --------
> > ; Move memory up/down (1 W to 4 GW)
> > ; x = source start address
> > ; y = destination start address
> > ; b = number of words to move
> > ; (4 GW are moved if b == 0 !!)
> > ;
> > :88020000 move: cpy #,x
> > :42420000 mvdown: lda [cc],x+
> > :a2440000 sta [cc],y+
> > :8c49fffd dbn [cc]mvdown,b
> > :5e4c0000 rts [cc]
> > :e4080000 adx #,b
> > :e8080000 ady #,b
> > :43020000 moveup: lda ,-x
> > :a3040000 sta ,-y
> > :8c09fffd dbn moveup,b
> > :5e0c0000 rts
> > [/code]
> >
> > Mike B.
>
> I think so, yes.
>
> I just knocked this up to move blocks around. It's for my hobby Forth
> system running on antiquated (>30 years old) hardware. Think 5.25"
> floppies and you're in the ball park.
>
> It uses locals. From some quick experiments, locals on a dumb (non-
> optimising) ITC makes things faster. The reason? All the stack juggling
> goes away. Those ROTs DUPs SWAPs etc are burning up time just getting
> the stack arranged. Locals on a dumb system takes that away. The
> argument doesn't hold on modern optimising systems.
>
> Anyway, it's moot... The disk I/O is millions of times slower than
> the code! But locals sure makes it easy... Like falling of a log.
>
> Ignore FLUSH? It just checks the block buffers and one or more is
> not flushed (dirty?) it offers the choice to do a flush first.
>
> : movblk ( src dest cnt -- )
> locals{ src dest cnt cpydir }
> set cnt set dest set src
> src dest < if
> cnt 1- +set src
> cnt 1- +set dest
> -1 set cpydir
> else
> 1 set cpydir
> then flush?
> cnt 0 do
> 2 spaces src . ." to " dest .
> src block drop 0 dest setblk 0 dirty flush
> cpydir +set src
> cpydir +set dest
> loop ;
Woops....
37 CLOAD LOCALS{
: flush? ( -- ) \ offer choice to flush if buffers are dirty
0 #buf @ 0 do i dirty? or loop if ." Flush? (Y/N)" key dup
ascii Y = swap ascii y = or if flush then then empty-buffers ;
: movblk ( src dest cnt -- )
locals{ src dest cnt cpydir }
set cnt set dest set src
src dest < if
cnt 1- +set src
cnt 1- +set dest
-1 set cpydir
else
1 set cpydir
then flush?
cnt 0 do
2 spaces src . ." to " dest .
src block drop 0 dest setblk 0 dirty flush
cpydir +set src
cpydir +set dest
loop ;
[toc] | [prev] | [next] | [standalone]
| From | "HAA" <someone@microsoft.com> |
|---|---|
| Date | 2015-08-20 04:39 +1000 |
| Message-ID | <mr2ifi$53m$1@speranza.aioe.org> |
| In reply to | #41382 |
Mark Wills wrote:
> >
> > I just knocked this up to move blocks around. It's for my hobby Forth
> > system running on antiquated (>30 years old) hardware. Think 5.25"
> > floppies and you're in the ball park.
> >
> > It uses locals. From some quick experiments, locals on a dumb (non-
> > optimising) ITC makes things faster. The reason? All the stack juggling
> > goes away. Those ROTs DUPs SWAPs etc are burning up time just getting
> > the stack arranged. Locals on a dumb system takes that away. The
> > argument doesn't hold on modern optimising systems.
> >
> > Anyway, it's moot... The disk I/O is millions of times slower than
> > the code! But locals sure makes it easy... Like falling of a log.
> > ...
>
> 37 CLOAD LOCALS{
> : flush? ( -- ) \ offer choice to flush if buffers are dirty
> 0 #buf @ 0 do i dirty? or loop if ." Flush? (Y/N)" key dup
> ascii Y = swap ascii y = or if flush then then empty-buffers ;
>
> : movblk ( src dest cnt -- )
> locals{ src dest cnt cpydir }
> set cnt set dest set src
> src dest < if
> cnt 1- +set src
> cnt 1- +set dest
> -1 set cpydir
> else
> 1 set cpydir
> then flush?
> cnt 0 do
> 2 spaces src . ." to " dest .
> src block drop 0 dest setblk 0 dirty flush
> cpydir +set src
> cpydir +set dest
> loop ;
Too many variables.
: bcopy ( src dest -- )
cr ." Copy " swap u. ." to " u.
\ swap block swap buffer 1024 cmove
\ update save-buffers
;
: movblk ( src dest cnt -- )
?dup if
swap 2 pick - >r 1- over +
r@ 0< if 1+ swap 1 else -1 then
r> 2swap do i 2dup + bcopy over +loop
then 2drop ;
10 12 bcopy
Copy 10 to 12 ok
10 12 5 movblk
Copy 14 to 16
Copy 13 to 15
Copy 12 to 14
Copy 11 to 13
Copy 10 to 12 ok
12 10 5 movblk
Copy 12 to 10
Copy 13 to 11
Copy 14 to 12
Copy 15 to 13
Copy 16 to 14 ok
[toc] | [prev] | [next] | [standalone]
| From | "Elizabeth D. Rather" <erather@forth.com> |
|---|---|
| Date | 2015-08-19 09:15 -1000 |
| Message-ID | <A9SdnbJokKR_SEnInZ2dnUU7-VednZ2d@supernews.com> |
| In reply to | #41381 |
On 8/18/15 8:35 AM, Mark Wills wrote:
> On Tuesday, 18 August 2015 18:10:22 UTC+1, Michael Barry wrote:
>> On Tuesday, August 18, 2015 at 9:59:02 AM UTC-7, Mark Wills wrote:
>>>
>>>> : move ( from to count -- )
>>>> >r 2dup u< if
>>>> r> cmove>
>>>> else
>>>> r> cmove
>>>> then ;
>>>>
>>>> Better branch prediction accuracy:
>>>>
>>>> : move ( from to count -- )
>>>> >r 2dup dup r@ + within if
>>>> r> cmove
>>>> else
>>>> r> cmove>
>>>> then ;
>>>>
>>>> Both not tested.
>>>>
>>>> - anton
>>>> --
>>>>
>>>
>>> That's nice code, thank you. Mine also included WITHIN but your first
>>> example is neater IMO. I just tested it quickly and it seems to work fine.
>>>
>>> Thanks.
>>>
>>> Mark
>>
>> Isn't it true that the decision can be made based simply on whether source start is less than destination start, regardless of count? Mine does that, but CMOVE> and CMOVE have equivalent performance, which might mot always be the case.
>>
>> [code]
>>
>> ;----------- 65m32: smart move --------
>> ; Move memory up/down (1 W to 4 GW)
>> ; x = source start address
>> ; y = destination start address
>> ; b = number of words to move
>> ; (4 GW are moved if b == 0 !!)
>> ;
>> :88020000 move: cpy #,x
>> :42420000 mvdown: lda [cc],x+
>> :a2440000 sta [cc],y+
>> :8c49fffd dbn [cc]mvdown,b
>> :5e4c0000 rts [cc]
>> :e4080000 adx #,b
>> :e8080000 ady #,b
>> :43020000 moveup: lda ,-x
>> :a3040000 sta ,-y
>> :8c09fffd dbn moveup,b
>> :5e0c0000 rts
>> [/code]
>>
>> Mike B.
>
> I think so, yes.
>
> I just knocked this up to move blocks around. It's for my hobby Forth
> system running on antiquated (>30 years old) hardware. Think 5.25"
> floppies and you're in the ball park.
>
> It uses locals. From some quick experiments, locals on a dumb (non-
> optimising) ITC makes things faster. The reason? All the stack juggling
> goes away. Those ROTs DUPs SWAPs etc are burning up time just getting
> the stack arranged. Locals on a dumb system takes that away. The
> argument doesn't hold on modern optimising systems.
>
> Anyway, it's moot... The disk I/O is millions of times slower than
> the code! But locals sure makes it easy... Like falling of a log.
>
> Ignore FLUSH? It just checks the block buffers and one or more is
> not flushed (dirty?) it offers the choice to do a flush first.
>
> : movblk ( src dest cnt -- )
> locals{ src dest cnt cpydir }
> set cnt set dest set src
> src dest < if
> cnt 1- +set src
> cnt 1- +set dest
> -1 set cpydir
> else
> 1 set cpydir
> then flush?
> cnt 0 do
> 2 spaces src . ." to " dest .
> src block drop 0 dest setblk 0 dirty flush
> cpydir +set src
> cpydir +set dest
> loop ;
>
The code with locals looks to me a lot messier than the earlier example.
In any case, a traditional block move would be quite simple:
: BMOVE (n1 n2 -- ) \ Moves the content of block n1 to n2.
>R BLOCK R> BLOCK 1024 CMOVE UPDATE ;
Very simple; locals would not be helpful. When BLOCK gets a buffer for a
block not already in memory, it will automatically write it to disk if
the selected buffer's contents are marked as UPDATED, so that's not
something the MOVE word needs to know about. Further, you know you can
count on there not being any overlap. If you have a version of MOVE that
does cell-wise moves, as Anton points out, that's preferable to CMOVE in
this case.
Cheers,
Elizabeth
--
==================================================
Elizabeth D. Rather (US & Canada) 800-55-FORTH
FORTH Inc. +1 310.999.6784
5959 West Century Blvd. Suite 700
Los Angeles, CA 90045
http://www.forth.com
"Forth-based products and Services for real-time
applications since 1973."
==================================================
[toc] | [prev] | [next] | [standalone]
| From | "HAA" <someone@microsoft.com> |
|---|---|
| Date | 2015-08-28 22:39 +1000 |
| Message-ID | <mrpknd$37p$1@speranza.aioe.org> |
| In reply to | #41381 |
Mark Wills wrote:
>
> It uses locals. From some quick experiments, locals on a dumb (non-
> optimising) ITC makes things faster. The reason? All the stack juggling
> goes away. Those ROTs DUPs SWAPs etc are burning up time just getting
> the stack arranged. Locals on a dumb system takes that away. The
> argument doesn't hold on modern optimising systems.
I implemented TurboForth locals for LMI PC/Forth 3.2 (8086 ITC)
and ran a benchmark based on MOVBLK with and without locals.
A Pentium PC was used for the test.
Speed (I/O and CMOVE code replaced with 2DROP)
locals without locals
63 sec 52 sec
Code size (less headers)
locals without locals
122 bytes 92 bytes
Using an 8086 DTC forth
locals without locals
21 sec 9 sec
The benchmark used for the test is shown below. I'll post the source for
the LMI TurboForth locals if anyone wants it and you have no objection.
Your website doesn't mention whether derivative works are permitted.
13
0 \ TEST2
1
2 : bcopy ( src dest -- )
3 \ CR ." Copy " SWAP U. ." to " U.
4 SWAP BLOCK SWAP BUFFER 1024 CMOVE UPDATE FLUSH
5 ;
6 : movblk1 ( src dest cnt -- )
7 ?DUP IF
8 SWAP 2 PICK - >R OVER +
9 R@ 0< IF SWAP 1 ELSE 1- -1 THEN
10 R> 2SWAP DO I 2DUP + 2DROP ( bcopy) OVER +LOOP
11 THEN 2DROP ;
12
13
14
15
14
0 \ TEST2
1
2 : movblk2 ( src dest cnt -- )
3 LOCALS{ src dest cnt cpydir }
4 SET cnt SET dest SET src
5 1 SET cpydir src dest < IF
6 cnt 1- +SET src cnt 1- +SET dest -1 SET cpydir
7 THEN ( flush? ) cnt 0 ?DO
8 \ 2 SPACES src . ." to " dest .
9 \ src block drop 0 dest setblk 0 dirty flush
10 \ src BLOCK dest BUFFER 1024 CMOVE UPDATE FLUSH
11 src dest 2DROP
12 cpydir +SET src cpydir +SET dest
13 LOOP ;
14
15
15
0 \ TEST2
1 : T1 7 EMIT 20 0 DO
2 0 0 DO 10 12 5 movblk1 12 10 5 movblk1 LOOP
3 LOOP 7 EMIT ;
4
5 : T2 7 EMIT 20 0 DO
6 0 0 DO 10 12 5 movblk2 12 10 5 movblk2 LOOP
7 LOOP 7 EMIT ;
8
9
10
11
12
13
14
15
[toc] | [prev] | [next] | [standalone]
| From | Coos Haak <chforth@hccnet.nl> |
|---|---|
| Date | 2015-08-28 15:06 +0200 |
| Message-ID | <17n3lioulkme0$.1sc8iaelhms65$.dlg@40tude.net> |
| In reply to | #41592 |
Op Fri, 28 Aug 2015 22:39:42 +1000 schreef HAA:
> Mark Wills wrote:
>>
>> It uses locals. From some quick experiments, locals on a dumb (non-
>> optimising) ITC makes things faster. The reason? All the stack juggling
>> goes away. Those ROTs DUPs SWAPs etc are burning up time just getting
>> the stack arranged. Locals on a dumb system takes that away. The
>> argument doesn't hold on modern optimising systems.
>
> I implemented TurboForth locals for LMI PC/Forth 3.2 (8086 ITC)
> and ran a benchmark based on MOVBLK with and without locals.
> A Pentium PC was used for the test.
>
> Speed (I/O and CMOVE code replaced with 2DROP)
>
> locals without locals
> 63 sec 52 sec
>
> Code size (less headers)
>
> locals without locals
> 122 bytes 92 bytes
>
> Using an 8086 DTC forth
>
> locals without locals
> 21 sec 9 sec
>
> The benchmark used for the test is shown below. I'll post the source for
> the LMI TurboForth locals if anyone wants it and you have no objection.
> Your website doesn't mention whether derivative works are permitted.
>
> 13
> 0 \ TEST2
> 1
> 2 : bcopy ( src dest -- )
> 3 \ CR ." Copy " SWAP U. ." to " U.
> 4 SWAP BLOCK SWAP BUFFER 1024 CMOVE UPDATE FLUSH
> 5 ;
> 6 : movblk1 ( src dest cnt -- )
> 7 ?DUP IF
> 8 SWAP 2 PICK - >R OVER +
> 9 R@ 0< IF SWAP 1 ELSE 1- -1 THEN
> 10 R> 2SWAP DO I 2DUP + 2DROP ( bcopy) OVER +LOOP
> 11 THEN 2DROP ;
> 12
> 13
> 14
> 15
>
> 14
> 0 \ TEST2
> 1
> 2 : movblk2 ( src dest cnt -- )
> 3 LOCALS{ src dest cnt cpydir }
> 4 SET cnt SET dest SET src
> 5 1 SET cpydir src dest < IF
> 6 cnt 1- +SET src cnt 1- +SET dest -1 SET cpydir
> 7 THEN ( flush? ) cnt 0 ?DO
> 8 \ 2 SPACES src . ." to " dest .
> 9 \ src block drop 0 dest setblk 0 dirty flush
> 10 \ src BLOCK dest BUFFER 1024 CMOVE UPDATE FLUSH
> 11 src dest 2DROP
> 12 cpydir +SET src cpydir +SET dest
> 13 LOOP ;
> 14
> 15
>
> 15
> 0 \ TEST2
> 1 : T1 7 EMIT 20 0 DO
> 2 0 0 DO 10 12 5 movblk1 12 10 5 movblk1 LOOP
> 3 LOOP 7 EMIT ;
> 4
> 5 : T2 7 EMIT 20 0 DO
> 6 0 0 DO 10 12 5 movblk2 12 10 5 movblk2 LOOP
> 7 LOOP 7 EMIT ;
> 8
> 9
> 10
> 11
> 12
> 13
> 14
> 15
Why the FLUSH? BUFFER knows when to write an UPDATEd blockbuffer.
groet Coos
[toc] | [prev] | [next] | [standalone]
| From | "HAA" <someone@microsoft.com> |
|---|---|
| Date | 2015-08-29 17:15 +1000 |
| Message-ID | <mrrmin$kct$1@speranza.aioe.org> |
| In reply to | #41594 |
Coos Haak wrote: > > Why the FLUSH? BUFFER knows when to write an UPDATEd blockbuffer. > > groet Coos BUFFER won't FLUSH the last block.
[toc] | [prev] | [next] | [standalone]
| From | Coos Haak <chforth@hccnet.nl> |
|---|---|
| Date | 2015-08-29 13:24 +0200 |
| Message-ID | <yk9m84rtqpwe.1recy578ttef0$.dlg@40tude.net> |
| In reply to | #41602 |
Op Sat, 29 Aug 2015 17:15:27 +1000 schreef HAA: > Coos Haak wrote: >> >> Why the FLUSH? BUFFER knows when to write an UPDATEd blockbuffer. >> >> groet Coos > > BUFFER won't FLUSH the last block. Admitted, but once is enough. groet Coos
[toc] | [prev] | [next] | [standalone]
| From | "HAA" <someone@microsoft.com> |
|---|---|
| Date | 2015-08-31 11:38 +1000 |
| Message-ID | <ms0b2s$m6$1@speranza.aioe.org> |
| In reply to | #41605 |
Coos Haak wrote: > Op Sat, 29 Aug 2015 17:15:27 +1000 schreef HAA: > > > Coos Haak wrote: > >> > >> Why the FLUSH? BUFFER knows when to write an UPDATEd blockbuffer. > >> > >> groet Coos > > > > BUFFER won't FLUSH the last block. > > Admitted, but once is enough. > > groet Coos For this application there is little to be gained putting FLUSH outside the loop.
[toc] | [prev] | [next] | [standalone]
| From | "Elizabeth D. Rather" <erather@forth.com> |
|---|---|
| Date | 2015-08-29 07:59 -1000 |
| Message-ID | <3LKdncZ6heGDbnzInZ2dnUU7-QGdnZ2d@supernews.com> |
| In reply to | #41602 |
On 8/28/15 9:15 PM, HAA wrote: > Coos Haak wrote: >> >> Why the FLUSH? BUFFER knows when to write an UPDATEd blockbuffer. >> >> groet Coos > > BUFFER won't FLUSH the last block. BUFFER should write the content of any block that has been marked UPDATEd before reusing that buffer. You really only need to FLUSH when you're about to shut down the computer. Cheers, Elizabeth -- ================================================== Elizabeth D. Rather (US & Canada) 800-55-FORTH FORTH Inc. +1 310.999.6784 5959 West Century Blvd. Suite 700 Los Angeles, CA 90045 http://www.forth.com "Forth-based products and Services for real-time applications since 1973." ==================================================
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | comp.lang.forth
csiph-web