Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 20 May 1997 18:11:42 -0600
From:      Brett Glass <brett@lariat.org>
To:        John-Mark Gurney <gurney_j@resnet.uoregon.edu>
Cc:        rberndt@nething.com, WELCHDW@wofford.edu, HARDWARE@FreeBSD.ORG
Subject:   Re: isa bus and boca multiport boards
Message-ID:  <3.0.1.32.19970520181142.00734e08@lariat.org>
In-Reply-To: <19970520194401.23424@hydrogen.nike.efn.org>
References:  <3.0.1.32.19970520125159.006dbe70@lariat.org> <8825649D.00771D31.00@IWND1.infoworld.com> <3.0.1.32.19970520125159.006dbe70@lariat.org>

next in thread | previous in thread | raw e-mail | index | archive | help
At 07:44 PM 5/20/97 -0700, you wrote:
 
>well... this won't do any good... as right now when COM_MULTIPORT is
>used all the sio ports are scanned until they scan without hitting any
>change (input, signal change)...  probably what should go in before this
>is splitting the intrrupt routine to only scan the ports that are on a
>certain board...  this shouldn't be THAT hard to do... and I've thought
>about doing it...

I was under the impression that this is what was already done, but now that
I look at it, I see that you're right! The code loops on a variable called
"unit", incrementing it from 0 to the precompiled constant NSIO. This can
waste a great deal of time, especially since the interrupts are
edge-triggered and the list is scanned at least twice per interrupt.

Here are some other improvements that could be made to the code, based on a
quick analysis:

1) The code looks at a flag called "gone" on each and every port (present
or not) during each and every interrupt service. Since the presence or
absence of a port is determined at boot time, it'd be MUCH more efficient
if the code worked down a linear list of only the ports that were present
and on the relevant IRQ.

The edge-catching algorithm is also less efficient than it might be. To
make sure you haven't missed an edge, you must scan the UARTs and get ALL
THE WAY AROUND THE LIST ONCE without finding any more ports to service. You
can then return from the ISR. The two best ways to do this are (a) set a
counter to the number of UARTS and decrement as you traverse the list
circularly, or (b) store the number (or port address) of the last UART that
had an interrupt pending. Scan the list in a circular manner until you get
back to the same UART without finding anything else to service. The current
code doesn't do this efficiently; it always does an end-to-end scan of the
list instead of stopping at the point of the last interrupt service. In
fact, it may scan as many as NSIO-1 extra ports on each interrupt. On a
system with a many serial ports, this is a LOT of extra time.

Also, rather than dereferencing the pointer "com" again and again, the ISR
could selectively enregister parts of the record that contain the comm
port's statistics. 

I also see a subroutine call that could be optimized out.

Finally, some things are variables that needn't be, such as I/O port
numbers. Memory accesses are expensive and increments and decrements are
cheap (or free due to pipelining if instructions are ordered properly). So,
in my code, I've found it's faster to load the interrupt status register
port number for the UART, then increment and decrement as needed rather
than doing more loads to obtain other register numbers. On the Intel
processors, increments and decrements don't have many scheduling
constraints; they've been optimized so that they rarely cause pipeline
stalls. And eliminating the stored port numbers can reduce the record size
dramatically, making it easy to enregister things.

I don't know what the policy on ASM code is in FreeBSD, but this seems like
an opportunity to do some VERY serious optimization where it's much needed!

--Brett




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3.0.1.32.19970520181142.00734e08>