M
Martin Gregorie
I've found a swing performance issue I don't understand. I'd appreciate
an explanation for what I'm getting and especially any suggestion for
fixing it.
I have written a simple Java terminal emulator, JTerm, which uses a
JTextArea to implement its screen. Structure is simple: its a normal
model/view/display structured application whose main thread handles
keyboard input and transmission to the remote system. A worker thread is
used to capture and display incoming data from the remote system.
When I first wrote the emulator, I used an extended non-terminating
Thread with this logic in its run() method:
while (again)
{
try
{
sleep(waitTime);
model.scanForData();
}
catch (InterruptedException ex)
{
waitTime = MINWAIT;
}
waitTime *= 2;
waitTime = (waitTime > MAXWAIT ? MAXWAIT : waitTime);
}
Every time a key is typed the thread is interrupted to make sure it
starts polling fast. The model's scanForData() method polls for data
from the remote system and puts it into the display via the
JTextArea.replaceRange() method. This worked smoothly, except that any
time I typed at a reasonable rate the JTerm bombed out with a failure to
get a writelock on the default document underlying JTextArea.
Yesterday I re-implemented the thread loop logic as an ActionListener
that's fired by a javax.swing.Timer. The variable loop timing is
achieved by setting the Timer's initial delay to MINWAIT and restarting
it whenever a key is typed. I moved the delay doubling logic into the
model.scanForData() method. This has cured the writelock failures by
executing the model.scanForData() method as part of the Swing
event-dispatching thread, *but* the perceived system performance has
deteriorated hugely.
It looks as though the screen update is now slowing the scan loop down
for long enough that huge volumes of data (anything up to 900 bytes) are
arriving while the screen is being updated despite the loop timer being
set for typically 8 or 16 mS. As the serial line is 9600 baud something
must be adding a second to the scan cycle in the terminal emulator:
nothing else in the entire setup has changed.
Here's the whole system in summary:
JTerm, the Java terminal emulator, is an application I wrote to provide
worst-case performance testing for my SerialPort package. JTerm sends
all keystrokes to the remote system as they are typed and only updates
its display with date received from the remote system, i.e. its a full
duplex terminal emulator with a 24 x 80 display area.
SerialPort runs entirely in user mode. It extends Java by providing
access to serial ports via an interface class and does not require any
changes to the supporting operating system. It's available on
SourceForge if you want to look at it though the current download still
contains the flaky version of JTerm. The new JTerm version will be put
up within 24 hours.
Here's a block diagram:
JTerm - the Java terminal emulator logic and gui
SerialPort - the interface class
|
| - a TCP/IP sockets connection
|
spd - a high performance server written in C
:
: - 9600 baud serial connection
:
remote system - a 25 MHz 68020 system running OS-9 v2.4.
JTerm logs in and runs commands via its shell.
spd buffers input and output serial port streams separately.
Asynchronous i/o is used to move bytes between the buffers and the
associated serial port. Blocks of data are transferred between the
application and buffers over the socket connection, so both i/o streams
are optimized for maximum throughput and minimum overhead.
JTerm and spd are on separate Linux systems on my house LAN. Both are
slow: a P300 and a K6/266 respectively. Single characters make the round
trip in under 4 mS. With the loop delay set to MINWAIT (4 mS) one
character can be sent and four received within the timeout interval.
When I'm sending a command to OS-9 I can type at my normal speed and not
have to wait after typing a key before it appears on screen.
The performance problem only occurs if something I type displays a
significant amount of data.
Any and all suggestions for improving the JTerm emulator will be
gratefully received.
an explanation for what I'm getting and especially any suggestion for
fixing it.
I have written a simple Java terminal emulator, JTerm, which uses a
JTextArea to implement its screen. Structure is simple: its a normal
model/view/display structured application whose main thread handles
keyboard input and transmission to the remote system. A worker thread is
used to capture and display incoming data from the remote system.
When I first wrote the emulator, I used an extended non-terminating
Thread with this logic in its run() method:
while (again)
{
try
{
sleep(waitTime);
model.scanForData();
}
catch (InterruptedException ex)
{
waitTime = MINWAIT;
}
waitTime *= 2;
waitTime = (waitTime > MAXWAIT ? MAXWAIT : waitTime);
}
Every time a key is typed the thread is interrupted to make sure it
starts polling fast. The model's scanForData() method polls for data
from the remote system and puts it into the display via the
JTextArea.replaceRange() method. This worked smoothly, except that any
time I typed at a reasonable rate the JTerm bombed out with a failure to
get a writelock on the default document underlying JTextArea.
Yesterday I re-implemented the thread loop logic as an ActionListener
that's fired by a javax.swing.Timer. The variable loop timing is
achieved by setting the Timer's initial delay to MINWAIT and restarting
it whenever a key is typed. I moved the delay doubling logic into the
model.scanForData() method. This has cured the writelock failures by
executing the model.scanForData() method as part of the Swing
event-dispatching thread, *but* the perceived system performance has
deteriorated hugely.
It looks as though the screen update is now slowing the scan loop down
for long enough that huge volumes of data (anything up to 900 bytes) are
arriving while the screen is being updated despite the loop timer being
set for typically 8 or 16 mS. As the serial line is 9600 baud something
must be adding a second to the scan cycle in the terminal emulator:
nothing else in the entire setup has changed.
Here's the whole system in summary:
JTerm, the Java terminal emulator, is an application I wrote to provide
worst-case performance testing for my SerialPort package. JTerm sends
all keystrokes to the remote system as they are typed and only updates
its display with date received from the remote system, i.e. its a full
duplex terminal emulator with a 24 x 80 display area.
SerialPort runs entirely in user mode. It extends Java by providing
access to serial ports via an interface class and does not require any
changes to the supporting operating system. It's available on
SourceForge if you want to look at it though the current download still
contains the flaky version of JTerm. The new JTerm version will be put
up within 24 hours.
Here's a block diagram:
JTerm - the Java terminal emulator logic and gui
SerialPort - the interface class
|
| - a TCP/IP sockets connection
|
spd - a high performance server written in C
:
: - 9600 baud serial connection
:
remote system - a 25 MHz 68020 system running OS-9 v2.4.
JTerm logs in and runs commands via its shell.
spd buffers input and output serial port streams separately.
Asynchronous i/o is used to move bytes between the buffers and the
associated serial port. Blocks of data are transferred between the
application and buffers over the socket connection, so both i/o streams
are optimized for maximum throughput and minimum overhead.
JTerm and spd are on separate Linux systems on my house LAN. Both are
slow: a P300 and a K6/266 respectively. Single characters make the round
trip in under 4 mS. With the loop delay set to MINWAIT (4 mS) one
character can be sent and four received within the timeout interval.
When I'm sending a command to OS-9 I can type at my normal speed and not
have to wait after typing a key before it appears on screen.
The performance problem only occurs if something I type displays a
significant amount of data.
Any and all suggestions for improving the JTerm emulator will be
gratefully received.