2001-03-22 18:24:37

by Geir Thomassen

[permalink] [raw]
Subject: Serial port latency

Hi.

My program controls a device (a programmer for microcontrollers) via the
serial port. The program sits in a tight loop, writing a few (typical 6)
bytes to the port, and waits for a few (typ. two) bytes to be returned from
the programmer.

The program works, but it is very slow. I use an oscilloscope to monitor the
serial lines, and notices that there is a large delay between the returned
data, and the next new command. I really don't know if the delay is on the
sending or the receiving side (or both).

This is what the program does:

fd=open("/dev/ttyS0",O_NOCTTY | O_RDWR);

tcsetattr(fd,TCSANOW, &tio); /* setting baud, parity, raw mode, etc */

while() {
write( 6 bytes); /* send command */
read( 2 bytes); /* wait for reply */
}


The device on the serial port responds in typ. 10 ms, but the software uses
over 500ms to get the reply and send the next command. Why is this happening ?
I have a feeling that there is something obvious I am missing (like line
buffering, but that's a stdio (libc) thing, isn't it ?).

BTW, I am running a 2.2 kernel ....

Geir, [email protected]


2001-03-22 20:05:17

by Geir Thomassen

[permalink] [raw]
Subject: Re: Serial port latency

Trent Jarvi wrote:
>
> Hi,
>
> I'm not on the kernel list. I just ran across your email while looking at the
> weekly archive.
>
> I think you want to enable software flow control.
>
> tcgetattr( fd, &ttyset );
> ttyset.c_iflag |= IXOFF;
> tcsetattr( fd, TCSANOW, &ttyset );
>

Just tested it, it didn't change anything. The response from the controller
can contain ^S/^Q, so it would be a bad idea anyway ....

> Someone reported that the Java CommAPI driver at http://www.rxtx.org got
> 150-200ms latency with (9600,N,8,1,XON/XOFF). Beyond that you may have to
> look at something like the realtime support. I guess 2 ms is normal on
> win98.

Win98 is the problem I am trying to solve with my program ...

> Since you have the scope hooked up you may look at hardware flow control too.
>
> tcgetattr( fd, &ttyset );
> ttyset.c_cflag |= HARDWARE_FLOW_CONTROL;
> tcsetattr( fd, TCSANOW, &ttyset );

Do you mean CRTSCTS ? HARDWARE_FLOW_CONTROL is not defined in my header files.
I use CLOCAL, which should make the driver ignore modem control lines.

> Let me know if you find anything out. I'm the maintainer of rxtx and would
> be interested in documenting this for others.

sure ...

> --
> Trent Jarvi
> [email protected]

Thanks anyway

Geir

2001-03-22 20:10:17

by Theodore Ts'o

[permalink] [raw]
Subject: Re: Serial port latency

On Thu, Mar 22, 2001 at 07:21:28PM +0100, Geir Thomassen wrote:
> My program controls a device (a programmer for microcontrollers) via the
> serial port. The program sits in a tight loop, writing a few (typical 6)
> bytes to the port, and waits for a few (typ. two) bytes to be returned from
> the programmer.

Check out the man page for the "low_latency" configuration parameter
in the setserial man page. This will cause the serial driver to burn
a small amount of additional CPU overhead when processing characters,
but it will lower the time between when characters arrive at the
RS-232 port and when they are made available to the user program. The
preferable solution is to use a intelligent windowing protocol that
isn't heavily latency dependent (all modern protocols, such as kermit,
zmodem, tcp/ip, etc. do this). But if you can't, using setserial to
set the "low_latency" flag will allow you to work around a dumb
communications protocol.

- Ted

2001-03-22 20:16:47

by Trent Jarvi

[permalink] [raw]
Subject: Re: Serial port latency

On Thu, 22 Mar 2001, Geir Thomassen wrote:

> Trent Jarvi wrote:
> >
> > Hi,
> >
> > I'm not on the kernel list. I just ran across your email while looking at the
> > weekly archive.
> >
> > I think you want to enable software flow control.
> >
> > tcgetattr( fd, &ttyset );
> > ttyset.c_iflag |= IXOFF;
> > tcsetattr( fd, TCSANOW, &ttyset );
> >
>
> Just tested it, it didn't change anything. The response from the controller
> can contain ^S/^Q, so it would be a bad idea anyway ....
>
> > Someone reported that the Java CommAPI driver at http://www.rxtx.org got
> > 150-200ms latency with (9600,N,8,1,XON/XOFF). Beyond that you may have to
> > look at something like the realtime support. I guess 2 ms is normal on
> > win98.
>
> Win98 is the problem I am trying to solve with my program ...
>
> > Since you have the scope hooked up you may look at hardware flow control too.
> >
> > tcgetattr( fd, &ttyset );
> > ttyset.c_cflag |= HARDWARE_FLOW_CONTROL;
> > tcsetattr( fd, TCSANOW, &ttyset );
>
> Do you mean CRTSCTS ? HARDWARE_FLOW_CONTROL is not defined in my header files.
> I use CLOCAL, which should make the driver ignore modem control lines.
>

Ya.. My bad. I use that to support multiple platforms

#ifdef CRTSCTS
#define HARDWARE_FLOW_CONTROL CRTSCTS
#else

Do you happen to have shared interupts enabled in the kernel?

> > Let me know if you find anything out. I'm the maintainer of rxtx and would
> > be interested in documenting this for others.
>
> sure ...
>
> > --
> > Trent Jarvi
> > [email protected]
>
> Thanks anyway
>
> Geir
>

--
Trent Jarvi
[email protected]

2001-03-22 20:34:27

by Geir Thomassen

[permalink] [raw]
Subject: Re: Serial port latency

Theodore Tso wrote:
>
> On Thu, Mar 22, 2001 at 07:21:28PM +0100, Geir Thomassen wrote:
> > My program controls a device (a programmer for microcontrollers) via the
> > serial port. The program sits in a tight loop, writing a few (typical 6)
> > bytes to the port, and waits for a few (typ. two) bytes to be returned from
> > the programmer.
>
> Check out the man page for the "low_latency" configuration parameter
> in the setserial man page. This will cause the serial driver to burn
> a small amount of additional CPU overhead when processing characters,
> but it will lower the time between when characters arrive at the
> RS-232 port and when they are made available to the user program. The
> preferable solution is to use a intelligent windowing protocol that
> isn't heavily latency dependent (all modern protocols, such as kermit,
> zmodem, tcp/ip, etc. do this). But if you can't, using setserial to
> set the "low_latency" flag will allow you to work around a dumb
> communications protocol.
>

I have tried this on both a stock Redhat 7.0 kernel and on 2.2.19pre5 with
your serial-5.05 driver, and I could not measure any difference with and
without the "low_latency" parameter to setserial ....

#setserial -a /dev/ttyS1
/dev/ttyS1, Line 1, UART: 16550A, Port: 0x02f8, IRQ: 3
Baud_base: 115200, close_delay: 50, divisor: 0
closing_wait: 3000
Flags: spd_normal skip_test low_latency


The serial port chip is 16550A, which has a built in fifo. Can this be
the source of my problems ?

Geir

2001-03-22 20:56:59

by Paul Fulghum

[permalink] [raw]
Subject: Re: Serial port latency

> The serial port chip is 16550A, which has a built in fifo. Can this be
> the source of my problems ?
>
> Geir

I thought about that. If the number of receive bytes in the RX FIFO
is less that the trigger level then a timeout has to occur before
getting the next receive data interrupt.

The 16550AF data book says that this timeout is 4 characters
from when the last byte is received. This is a maximum of 160ms
at 300bps (when using 12bit characters: 1 start + 8 data + parity + 2 stop).

So this would be smaller at 9600 and could not account
for the 500ms delay.

Paul Fulghum [email protected]
Microgate Corporation http://www.microgate.com


2001-03-22 21:04:39

by Geir Thomassen

[permalink] [raw]
Subject: Re: Serial port latency

Jim Penny wrote:
>
> On Thu, Mar 22, 2001 at 07:21:28PM +0100, Geir Thomassen wrote:
> > My program controls a device (a programmer for microcontrollers) via the
> > serial port. The program sits in a tight loop, writing a few (typical 6)
> > bytes to the port, and waits for a few (typ. two) bytes to be returned from
> > the programmer.
> >
> > The program works, but it is very slow. I use an oscilloscope to monitor the
> > serial lines, and notices that there is a large delay between the returned
> > data, and the next new command. I really don't know if the delay is on the
> > sending or the receiving side (or both).
> >


>
> 500ms seems a bit too long, but the quick answer is scheduler latency.
> You will certainly be scheduled out by the read, after all, it is not
> your program that is doing the read, but the kernel. I think you are
> scheduled out after the write, as well.

I do believe the write will make the kernel write the first byte
into the UART transmit buffer directly. If this is the case, then the
data should appear on the serial lines almost immediately. There might be a
delay before the bottom half handler process the byte (or is the bottom half
only used on receive ?), but I do believe that this happens before the next
process is scheduled (BH handlers are all finished before any syscalls returns).
If this is the case, then scheduling out on write should not do any harm.

>
> Your task is then sitting idle until the scheduler's next pass, if nothing
> else is happening, an interrupt is scheduled on the RTC, the CPU is set to
> idle power, and your system sleeps until the RTC wakes it back up, and
> the schedule queue is re-examined.
>
> This normally implies a wait of at least a jiffy after every read.
>


Isn't a jiffy 10ms on i386 ? Scheduling delays should not be any
more than say 50 ms, but I am measuring 500ms. I could live with
50ms, which would make my program finish in 3 min. Now it is using
30 min !!

>
> (But your time seems really excessive.)

Yep :-(

> The usual cure is to write a custom driver which does a single
> read/write command. If, as I recall, you are scheduled out on reads
> as well as writes, this lets you get rid of half the jiffies.

That could be the solution to my problem, but I won't start on that
before I understand what the problem is ...


Geir, [email protected]

2001-03-22 21:48:39

by Manfred Spraul

[permalink] [raw]
Subject: Re: Serial port latency

Is the computer otherwise idle?
I've seen one unexplainable report with atm problems that disappeared
(!) if a kernel compile was running.

Could you try to run a simple cpu hog (with nice 20)?

<<
main()
{
for(;;) getpid();
}
<<

I'm aware of one bug that could cause a delay of up to 20 ms (cpu_idle()
doesn't check for pending softirq's before sleeping), but that doesn't
explain your 500 ms delay.

--
Manfred

2001-03-22 21:54:00

by Jonathan Lundell

[permalink] [raw]
Subject: Re: Serial port latency

>This is what the program does:
>
> fd=open("/dev/ttyS0",O_NOCTTY | O_RDWR);
>
> tcsetattr(fd,TCSANOW, &tio); /* setting baud, parity, raw mode, etc */
>
> while() {
> write( 6 bytes); /* send command */
> read( 2 bytes); /* wait for reply */
> }

What are your settings for VTIME and VMIN?

--
/Jonathan Lundell.

2001-03-22 22:46:29

by Theodore Ts'o

[permalink] [raw]
Subject: Re: Serial port latency

On Thu, Mar 22, 2001 at 09:32:39PM +0100, Geir Thomassen wrote:
>
> The serial port chip is 16550A, which has a built in fifo. Can this be
> the source of my problems ?

Well, if you set the uart to be 16450 using setserial, this will cause
Linux to avoid enabling the FIFO. That will cause the loop to save
the 4 character times (which at 9600 bps is 4ms). If your original
protocol is writing six characters, and then reads 2 characters in a
tight loop, that means a total cycle takes 8ms, and disabling the FIFO
will have significant savings assuming that all other causes of
latencies have been removed. (The FIFO delay can cause a slowdown by
50%).

- Ted

2001-03-23 11:48:00

by Pavel Machek

[permalink] [raw]
Subject: Re: Serial port latency

Hi!

> My program controls a device (a programmer for microcontrollers) via the
> serial port. The program sits in a tight loop, writing a few (typical 6)
> bytes to the port, and waits for a few (typ. two) bytes to be returned from
> the programmer.
>
> The program works, but it is very slow. I use an oscilloscope to monitor the
> serial lines, and notices that there is a large delay between the returned
> data, and the next new command. I really don't know if the delay is on the
> sending or the receiving side (or both).
>
> This is what the program does:
>
> fd=open("/dev/ttyS0",O_NOCTTY | O_RDWR);
>
> tcsetattr(fd,TCSANOW, &tio); /* setting baud, parity, raw mode, etc */
>
> while() {
> write( 6 bytes); /* send command */
> read( 2 bytes); /* wait for reply */
> }
>
>
> The device on the serial port responds in typ. 10 ms, but the software uses
> over 500ms to get the reply and send the next command. Why is this happening ?
> I have a feeling that there is something obvious I am missing (like line
> buffering, but that's a stdio (libc) thing, isn't it ?).

Set HZ=1000 in include/asm/params.h and see if it helps.

Pavel
--
I'm [email protected]. "In my country we have almost anarchy and I don't care."
Panos Katsaloulis describing me w.r.t. patents at [email protected]

2001-03-23 14:54:19

by Geir Thomassen

[permalink] [raw]
Subject: Re: Serial port latency

Problem solved !

The main problem was that I didn't know that the equipment used
DTR as character acknowledge (not RTS/CTS which is common for flow
control). I didn't even bother to look at those lines with the
oscilloscope. Now the software runs fine with negligible latency.

Now the total latency is so low that the low_latency option to
setserial really matters, it reduces the total run time of my
program with 38 %

I don't get any measurable speed improvement by forcing the UART
to be detected as a 8250 or a 16450 though.

I have not tested with HZ=1000.

All in all, my problem is solved, thank you all.

Geir

2001-03-29 08:18:50

by Manfred Spraul

[permalink] [raw]
Subject: Re: Serial port latency

From: "Pavel Machek" <[email protected]>
> > Is the computer otherwise idle?
> > I've seen one unexplainable report with atm problems that
disappeared
> > (!) if a kernel compile was running.
>
> I've seen similar bugs. If you hook something on schedule_tq and
forget
> to set current->need_resched, this is exactly what you get.
>
I'm running with a patch that printk's if cpu_idle() is called while a
softirq is pending.
If I access the floppy on my K6/200 every track triggers the check, and
sometimes the console blanking code triggers it.

What about creating a special cpu_is_idle() function that the idle
functions must call before sleeping?

--
Manfred

2001-03-30 22:37:52

by Pavel Machek

[permalink] [raw]
Subject: Re: Serial port latency

Hi!

> > > Is the computer otherwise idle?
> > > I've seen one unexplainable report with atm problems that
> disappeared
> > > (!) if a kernel compile was running.
> >
> > I've seen similar bugs. If you hook something on schedule_tq and
> forget
> > to set current->need_resched, this is exactly what you get.
> >
> I'm running with a patch that printk's if cpu_idle() is called while a
> softirq is pending.
> If I access the floppy on my K6/200 every track triggers the check, and
> sometimes the console blanking code triggers it.

Seems floppy and console is buggy, then.

> What about creating a special cpu_is_idle() function that the idle
> functions must call before sleeping?

I'd say just fix all the bugs.
Pavel
--
The best software in life is free (not shareware)! Pavel
GCM d? s-: !g p?:+ au- a--@ w+ v- C++@ UL+++ L++ N++ E++ W--- M- Y- R+

2001-03-28 20:53:25

by Pavel Machek

[permalink] [raw]
Subject: Re: Serial port latency

Hi!

> Is the computer otherwise idle?
> I've seen one unexplainable report with atm problems that disappeared
> (!) if a kernel compile was running.

I've seen similar bugs. If you hook something on schedule_tq and forget
to set current->need_resched, this is exactly what you get.
--
Philips Velo 1: 1"x4"x8", 300gram, 60, 12MB, 40bogomips, linux, mutt,
details at http://atrey.karlin.mff.cuni.cz/~pavel/velo/index.html.

2001-04-01 09:05:41

by Manfred Spraul

[permalink] [raw]
Subject: Re: Serial port latency

--- 2.4/arch/i386/kernel/process.c Thu Feb 22 22:28:52 2001
+++ build-2.4/arch/i386/kernel/process.c Sun Apr 1 00:05:21 2001
@@ -73,6 +73,30 @@
hlt_counter--;
}

+/**
+ * cpu_is_idle - helper function for idle functions
+ *
+ * pm_idle functions must call this function to verify that
+ * the cpu is really idle. It must be called with disabled
+ * local interrupts.
+ * Return values:
+ * 0: cpu was not idle, local interrupts reenabled.
+ * 1: go into power saving mode, local interrupts are
+ * still disabled.
+*/
+static inline int cpu_is_idle(void)
+{
+ if (current->need_resched) {
+ __sti();
+ return 0;
+ }
+ if (softirq_active(smp_processor_id()) & softirq_mask(smp_processor_id())) {
+ __sti();
+ do_softirq();
+ return 0;
+ }
+ return 1;
+}
/*
* We use this if we don't have any better
* idle routine..
@@ -81,10 +105,8 @@
{
if (current_cpu_data.hlt_works_ok && !hlt_counter) {
__cli();
- if (!current->need_resched)
+ if (cpu_is_idle())
safe_halt();
- else
- __sti();
}
}



Attachments:
patch-proc (1.00 kB)

2001-04-10 00:35:55

by Andrea Arcangeli

[permalink] [raw]
Subject: Re: Serial port latency

On Sun, Mar 25, 2001 at 11:10:14PM +0000, Pavel Machek wrote:
> I've seen similar bugs. If you hook something on schedule_tq and forget
> to set current->need_resched, this is exactly what you get.

keventd fixes tq_scheduler case (tq_scheduler is dead).

Andrea