From willer@wtal.de
Received: by maskin (mbox dlanor)
 (with Cubic Circle's cucipop (v1.31 1998/05/13) Fri Jun  4 00:29:33 1999)
X-From_: willer@wtal.de Thu Jun  3 14:32:17 1999
Received: (from uucp@localhost)
	by maskin.ettnet.se (8.9.1a/8.8.8) id OAA11970
	for <dlanor@ettnet.se>; Thu, 3 Jun 1999 14:32:16 +0200 (MET DST)
Received: from UNKNOWN(195.8.224.4), claiming to be "mail.kdt.de"
 via SMTP by maskin, id smtpdAAAa002un; Thu Jun  3 14:32:05 1999
Received: from [127.0.0.1] (line78.kdt.de [195.8.225.78])
	by mail.kdt.de (8.8.8/8.8.8) with SMTP id OAA06644
	for <dlanor@ettnet.se>; Thu, 3 Jun 1999 14:31:07 +0200
Date: Thu, 3 Jun 1999 14:31:07 +0200
Message-Id: <199906031231.OAA06644@mail.kdt.de>
To: dlanor@ettnet.se (Ulf Ronald Andersson)
From: willer@wtal.de (Stefan Willer)
Organization: (none)
Subject: STinG optimization
X-Mailer: NEWSie Version 0.94 (Atari)

Hi Ronald!

Appended you find my highly optimized version of the internet
checksum algorithm. It is about 20% faster compared to Peter's
checksum algorithm. It is shorter, too. It plugs right into
UDP.STX and TCP.STX.

(I prefer having only one source file, including it in both
modules, and selecting minor changes by defining a variable
PROTOCOL as appropriate.)

Also included is my optimized version of Peter's UDP.STX.
All changes to his original code can be included by setting
the variable OPTI.

Why optimize at all? Of course I do not optimize for space
on purpose! However, I did remove some 250 lines of code
from UDP.STX. This is just a cleaning-up process that I
like to do before doing any other optimizations, like
optimizing for speed. Assembly language is not as easy to
read. That's why I like to produce concise code. I seldom
use macros, because that tends to hinder peephole optimization.
My primary optimization goal for UDP.STX and TCP.STX was
speed. That's because the fastest ST that I have runs at 16MHz,
and I noticed up- and download rates weren't as fast as
my modem permits. Besides, I wanted to reduce the general
system load imposed by STinG to an absolute minimum. I did
not want to switch STinG off in the boot manager every time
I go offline and use some multimedia applications, which
need every bit of power available.

I know reading someone else's code is somewhat boring. I just
included it for reference. You may have a look if you find
the time.

I would like to highlight some changes, which I believe to be
particularly important, though.

I changed all calls to the semaphore routines to inline code.
This makes a measurable difference, especially since I also
changed the semaphore routines from C to 68k style. These are
busy waiting loops! They need to be fast.

I changed addressing modes from "32 bit direct" to "PC relative"
in a lot of places.

I did what they call "peephole optimization" in compiler construction,
i.e. removing useless compiler-generated instructions by inspecting
a local context. (Some particularly brain-dead examples are marked
by "Ahhh" and "Ouch".)

There are also some errors or inconsistencies. You can find those
by looking for "###".

Since CNget_char() is the one API function with most overhead,
you should propably have a look at that one. It is also the only
API function that can be used for line oriented ASCII protocols
like NNTP and SMTP without problems. CNgets() and CNget_NDB()
don't always work.

Other good candidates for optimization are those routines that
are called regularly during interrupt.

All these optimizations apply to TCP.STX as well. TCP is slower
by design, though. A good candidate for optimization in TCP.STX
are those code conversion (or state transition) routines. I don't
really know their purpose, because I don't have the sources.
Anyway, they basically take some small numbers as input and
return some other small numbers. They are clearly compiled C
switch statements which can be done much faster in assembly
language:

o  The compiler always compares the parameter of the
   switch statement against some upper bound, even if this
   bound will never be exceeded. 20 extra CPU cycles!
o  The compiler always uses 16 bit jump offsets. For the
   routines in question, 8 bit is sufficient, though. With
   8 bit jump offsets, no scaling of the switch parameter
   is required, and it can be used again in the case
   statements.

Another optimization is proposed in one of the relevant RFCs,
I think: Computing the internet checksum on-the-fly while
copying data. I did not try this yet.

I hope this hasn't been too much of a nuisance. It would be much
easier if I had some original sources.

Could you please include me in the STinG developer's mailing list?

By the way: I am using only so many characters per line, because
I like newspaper-style narrow text columns where your eyes don't
have to wander back and forth. I have a small font, too. I would
love to see yours, though!

I will refer to STinG 1.20 in a subsequent message.


Kindest Regards,
         Stefan Willer


--------------------- CUT HERE ------------------------------


begin 644 willer.zip
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
M82(``)_/```%``````````$`(````*,'``!51%`N4U!+!08`````!``$`-P`
(```G*@`````%
`
end


