Skip to contentSkip to conversation

Zero copy transmit

DISCUSSION Steve Modica 5 participants 12 messages Apr 29, 2003 – Apr 30, 2003

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

Hi All,

We are doing some experiementing with Altix systems (Itanium II with
NUMA) and we're taking a big hit from __copy_user traffic. We would
like to modify the write, writev, send and sendto interfaces such that
we can avoid the __copy_user call by marking pages copy-on-write (COW)
and handing them off to be transmitted. Since this requires TLB updates, we would only implement this code on platforms that defined themselves as capable of fast TLB updates.

There was a lot of concern expressed on the l-k alias about COW being difficult to support becaue of the TLB update issues, but NUMA systems have to be especially quick at TLB updates, so it's something we want to take advantage of.

I'm looking for comments and suggestions as to how we could do this without impacting other system types.

Best Regards!
Steve

Signature · 4 lines
Steve Modica
Manager - Networking Drivers Group
"Give a man a fish, and he will eat for a day, hit him with a fish and
he leaves you alone" - me
#1 lore raw
Quoted 7 lines · Steve Modica

We are doing some experiementing with Altix systems (Itanium II with NUMA) and we're taking a big hit from __copy_user traffic. We would like to modify the write, writev, send and sendto interfaces such that we can avoid the __copy_user call by marking pages copy-on-write (COW) and handing them off to be transmitted. Since this requires TLB updates, we would only implement this code on platforms that defined themselves as capable of fast TLB updates.

A much better way would be to use the POSIX aio interfaces. They support zero copy transmit, but don't require COW. Instead they just tell the user process when it is safe to touch the buffer again.

There was already some code to do aio TCP sending, but it didn't do zero copy and was not merged for some reason.

Also you can already do zero copy transmit using sendfile()

Linux basically has all the infrastructure you need for this already; just the high level interface to the AIO system calls is still missing.

-Andi

#2 lore raw
Quoted 8 lines · Andi Kleen

A much better way would be to use the POSIX aio interfaces. They support zero copy transmit, but don't require COW. Instead they just tell the user process when it is safe to touch the buffer again.

There was already some code to do aio TCP sending, but it didn't do zero copy and was not merged for some reason.

Also you can already do zero copy transmit using sendfile()

Users would need to rewrite all their apps to use either the async or sendfile method. That assumption seems a little broad.

I don't disagree that implementing the remainder of the AIO system calls would also be good, but is there something wrong with getting write et. al. to work with zero copy?

Robin Holt

#3 lore raw
Quoted 5 lines · Robin Holt
Quoted 4 lines · Andi Kleen

A much better way would be to use the POSIX aio interfaces. They support zero copy transmit, but don't require COW. Instead they just tell the user process when it is safe to touch the buffer again.

Quoted 7 lines
Quoted 4 lines

There was already some code to do aio TCP sending, but it didn't do zero copy and was not merged for some reason.

Also you can already do zero copy transmit using sendfile()

Users would need to rewrite all their apps to use either the async or sendfile method. That assumption seems a little broad.

In my experience only a few programs are performance critical in this way; and their developers/users usually do not mind changing their programs a bit to get the best performance. In fact they are always happy when they get such knobs from you ;)

Quoted 4 lines

I don't disagree that implementing the remainder of the AIO system calls would also be good, but is there something wrong with getting write et. al. to work with zero copy?

You have to ask DaveM/Alexey - they had it, but rejected it, apparently also based on some bad experiences on other operating systems.

I can see their point - e.g. in the worst case each write could trigger two TLB flush IPIs to all CPUs in the system (one to COW it and another to un COW it). You can copy a lot of data in the time it takes to process all of them, especially on a big machine.

-Andi

#4 lore raw
In reply to Andi Kleen
Quoted 16 lines · Andi Kleen
Quoted 5 lines · Steve Modica

We are doing some experiementing with Altix systems (Itanium II with
NUMA) and we're taking a big hit from __copy_user traffic. We would
like to modify the write, writev, send and sendto interfaces such that
we can avoid the __copy_user call by marking pages copy-on-write (COW)
and handing them off to be transmitted. Since this requires TLB updates, we would only implement this code on platforms that defined themselves as capable of fast TLB updates.

A much better way would be to use the POSIX aio interfaces. They support zero copy transmit, but don't require COW. Instead they just tell the user process when it is safe to touch the buffer again.

There was already some code to do aio TCP sending, but it didn't do zero copy and was not merged for some reason.

Quoted 6 lines

Also you can already do zero copy transmit using sendfile()

Linux basically has all the infrastructure you need for this already; just the high level interface to the AIO system calls is still missing.

-Andi

Hi Andi,

We are aware of sendfile() and used it for the purposes of proving that zero copy would make a big difference for us.

At issue is really application capture and customer adoption. There are
tons of apps and lots of engineers that know socket operations and write/writev. Asking all ISVs to recode for linux would leave them with two separate APIs to deal with. They would have send/sendto or write/writev on Solaris, HPUX and whatever else, and linux would have sendfile.

We really want to do this in such a way that it doesn't create a huge footprint (and we think we can) and we want to make sure we don't impact systems that can't take advantage of fast TLB updates.

Steve

Signature · 6 lines
Steve Modica
work: 651-683-3224
mobile: 651-261-3201
Manager - Networking Drivers Group
"Give a man a fish, and he will eat for a day, hit him with a fish and
he leaves you alone" - me
#5 lore raw
Quoted 6 lines

At issue is really application capture and customer adoption. There are tons of apps and lots of engineers that know socket operations and write/writev. Asking all ISVs to recode for linux would leave them with two separate APIs to deal with. They would have send/sendto or write/writev on Solaris, HPUX and whatever else, and linux would have sendfile.

aio_write / lio_listio exists on Solaris and HP/UX too.

(and even Windows; their completion port interfaces are very similar)

Quoted 4 lines

We really want to do this in such a way that it doesn't create a huge footprint (and we think we can) and we want to make sure we don't impact systems that can't take advantage of fast TLB updates.

So how do you avoid the two TLB flush IPIs to all CPUs that have the current mm mapped ?

-Andi

#6 lore raw
Quoted 7 lines · Andi Kleen
Quoted 2 lines

At issue is really application capture and customer adoption. There are
tons of apps and lots of engineers that know socket operations and write/writev. Asking all ISVs to recode for linux would leave them with two separate APIs to deal with. They would have send/sendto or write/writev on Solaris, HPUX and whatever else, and linux would have sendfile.

aio_write / lio_listio exists on Solaris and HP/UX too.

(and even Windows; their completion port interfaces are very similar)

Right.. although some might say that aio_write is used a lot less often than write or send.

It's hard to convince thousands of application writers to revisit stuff like this. It's a lot easier to bring the hardware feature in to the APIs that people just commonly use.

Quoted 9 lines
Quoted 3 lines

We really want to do this in such a way that it doesn't create a huge footprint (and we think we can) and we want to make sure we don't impact systems that can't take advantage of fast TLB updates.

So how do you avoid the two TLB flush IPIs to all CPUs that have the current mm mapped ?

-Andi

I could speculate about how we might avoid that, or I could speculate that even with those operations, it would still be faster, but I'd rather just demonstrate it with a patch.

Don't get me wrong, we would certainly drop any notions of this if we found that it was slower and I will be glad to post any results. The goal is to take advantage of the hardware to make things faster.

Going back to your example above, don't solaris and hpux also do COW for write and send? (I don't have their sources) If so, why would they do it if it's slower?

Steve

Signature · 6 lines
Steve Modica
work: 651-683-3224
mobile: 651-261-3201
Manager - Networking Drivers Group
"Give a man a fish, and he will eat for a day, hit him with a fish and
he leaves you alone" - me
#7 lore raw
Quoted 3 lines

Don't get me wrong, we would certainly drop any notions of this if we found that it was slower and I will be glad to post any results. The goal is to take advantage of the hardware to make things faster.

You have no hardware to make the remote TLB flushes fast ;)

I'm sure you can show it being an advantage with a single threaded process. But when you run it on a multithreaded application just with two threads it may look very different.

Quoted 3 lines

Going back to your example above, don't solaris and hpux also do COW for write and send? (I don't have their sources) If so, why would they do it if it's slower?

I don't know if they do. The only Unix I'm aware of that has zero copy sendmsg() is NetBSD and their focus does not seem to be SMP scalability.

I observed the problem recently just with swapping a big (10GB) process whose working set slightly exceeded the available memory.
kswapd was running on one CPU; the process on another. kswapd
was aging the pages of the memory hog all the time, which requires an unmapping and a remote TLB flush in the process' page tables. The result
was that two CPUs were 100% tied up in the kernel, just spinning on the page_table_lock of the mm and processing TLB IPIs (spinlock was ~50%; IPI overhead 40% or so). I predict that your proposed TLB flushing write will cause the same problem with lots of writes. It's more or less the same thing, except that kswapd has a builtin rate limit and runs only on a single CPU and write() has not.

Also last time I checked most Linux ports still used an single global spinlock for the TLB flush IPI. You would add a nice new hot lock to the network path.

-Andi

#8 lore raw
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

"Andi" == Andi Kleen <[email protected]> writes:

Andi> I don't know if they do. The only Unix I'm aware of that has zero copy Andi> sendmsg() is NetBSD and their focus does not seem to be SMP scalability.

NetBSD 1.6 is the first release with both zero-copy and SMP. (1.6.1 came out two weeks ago)

So, the focus was on making it work.
I would not read any more intent to it yet. Jason Thorpe is pretty smart.

]       ON HUMILITY: to err is human. To moo, bovine.           |  firewalls  [
]   Michael Richardson, Sandelman Software Works, Ottawa, ON    |net architect[
] [email protected] http://www.sandelman.ottawa.on.ca/ |device driver[

] panic("Just another Debian GNU/Linux using, kernel hacking, security guy"); [

#9 lore raw
In reply to Andi Kleen
Quoted 10 lines · Andi Kleen
Quoted 3 lines

Don't get me wrong, we would certainly drop any notions of this if we found that it was slower and I will be glad to post any results. The goal is to take advantage of the hardware to make things faster.

You have no hardware to make the remote TLB flushes fast ;)

I'm sure you can show it being an advantage with a single threaded process. But when you run it on a multithreaded application just with two threads it may look very different.

Last time I checked, the IA64 processor provides a ptc.g instruction for exactly this. The only hit we take from using it is Intel limits it to a single outstanding ptc.g pending machine wide. This is accomplished with a global spinlock. I would love to convince Intel to change this instruction, but that probably will not happen any time soon.

I will concede that the ptc.g instruction takes a considerable period of time on our 64 processor machines, but that comes out to a lot of local TLB coherence domains that need to be updated.

I believe there is a similar instruction for x86. Could someone verify this?

#10 lore raw
Quoted 5 lines

Last time I checked, the IA64 processor provides a ptc.g instruction for exactly this. The only hit we take from using it is Intel limits it to a single outstanding ptc.g pending machine wide. This is accomplished with a global spinlock. I would love to convince Intel to change this instruction, but that probably will not happen any time soon.

IA64 Linux doesn't use it at least. The 2.5 flush_tlb_mm calls smp_flush_tlb_mm which ends up doing IPIs. Same for flush_tlb_page - calls flush_tlb_range which calls sn2_global_tlb_purge, which does something complicated that also looks like an global IPI. It also takes a global spinlock.

Quoted 7 lines

I will concede that the ptc.g instruction takes a considerable period of time on our 64 processor machines, but that comes out to a lot of local TLB coherence domains that need to be updated.

I believe there is a similar instruction for x86. Could someone verify this?

Nope. x86 has to IPI for remote TLB flushes.

-Andi

Quoted 1 line
#11 lore raw
In reply to Steve Modica
Quoted 6 lines · Steve Modica

At issue is really application capture and customer adoption. There are tons of apps and lots of engineers that know socket operations and write/writev. Asking all ISVs to recode for linux would leave them with two separate APIs to deal with. They would have send/sendto or write/writev on Solaris, HPUX and whatever else, and linux would have sendfile.

Solaris and HPUX have sendfile, the HPUX one has a slightly different API, the Solaris one is modelled after Linux.