Re: epoll and nbio

Zombi <[email protected]> Thu, 7 Aug 2003 01:52:35 +0200
Newsgroups gmane.comp.java.seda.user
Message-ID <[email protected]>
 I think an implementation of an epoll based nbio will not have a tremendous 
performance gainment against the poll based nbio. Mostly because of the too 
complex interaction of the java and the native code. I mean when someone want 
to read data from a non-blocking socket, he have to :

(populate a SelectSet)
- call SelectSet.select();
    then the native code use a lot of JNI, to collect the necessary socket/set 
information,  issue a system call, then again with a lot of JNI encode the 
collected information to the java code 
- then the java code need to go through the results and issue a non-blocking 
read call (again with JNI) for every socket. This could be a big wastage if 
the protocol is simple, and man can predict, for example - that until the 
next 64kbytes arrive we don't have to do anything (except to collect the data 
:-)

So recently I'm thinking about an alternate, and simpler API instead of NBIO 
personally called Java Completion Ports (JCP) (because windows has a very 
similar API for this :) and concluded to the following draft:

interface CompletionPort {
  public void start();
  public void stop();

  public Handler register(NonblockingSocket);
  public void unregister(Handler);
}

interface SocketHandler {
 void enqueRead( Request );
 void enqueWrite( Request );
}

abstract class Request {
 byte[] buffer;
 int current_offset;
 int call_requestFinished_after_x_bytes_readed = 0;
 
 public abstract boolean requestFinished();
}

I hope it's simple enough ;-) (at least for me :)
And the usage of this API ( for a very silly protocol ;-)

NonblockingSocket socket = .....
CompletionPort cp = ...

cp.start();

Handler handler = cp.register(socket);

handler.enqueRead( new Request(4096) {
  public boolean requestFinished() {
	System.out.println("hello world ... we have "+getCurrentOffset()+" bytes");
	for (int i=0;i<getCurrentOffset();i++) {
		if (buffer[i]==0) {
			handler.enqueWrite( new DummyRequest( buffer ));
			return true;
		}
	}
	if (getCurrentOffset()==4096) {
		setCurrentOffset(0);
	}
	return false;
  }
}


(actually it will wait for a #0 byte, and then send back the 4k buffer, as I 
said, it's a very silly program :)
And now the gory details: 
 - the CompletionPort's  start method start a new event dispatch thread which 
do the followings:
  while (<stop not called>) {
	- do the necessary house keeping for the newly (un)registered sockets
	- call the big native "dispatchEvents" method
		- call the select/poll/epoll/kqueue/... sysfunction to gather readiness           
                  events
		- for every event check that there is an extant Request, and if present
		  call read/write (socket, request.buffer, request.current_offset )
		- check that the buffer has more byte than 
"request.call_requestFinished_after_x_bytes_readed" then call 
request.requestFinished()
  }

And that's all ... :-) (I hope:-)

 Pros and cons of this API:
+ simpler API - you don't have to care about the necessary bookkeeping, and 
with the a synchronization issues, you just request the data to send/receive, 
and declare to what to do after.
+ more portable - win32 has the necessary functions, so I'm sure that it will 
be a lot easier to port JCP to windows than the porting of NBIO to windows. 
And with this API we do not have to emulate a "select"-style event-collecting 
interface - which proved to not so scaleable, and performant.
+ better performance - because of the reduced number of JNI, and a possible 
OS-friendlyness :)
- mostly speculations, currently not exists :)
- currently no way to cancel a request - however i'm not sure that it's 
necessary. In my practice, I happily lived without it :-)

Uhhh ... that's all ... :)

What do you think about ? Is it worth implement it? 
Or am I missing something important? 

bye
 Zsombor




2003. július 31. 11.41 dátummal J. Robert von Behren ezt írta:
> Jared -
>
> I took a look at this several months ago, and ran into a couple of
> problems.  Here is what I remember of the situation:
>
>    * Make sure you use the epoll system call interface, rather than
> /dev/epoll, as that is what the kernel developers seem to have settled on.
>
>    * There is a fairly fundamental mismatch between the level-triggered
> nature of the NBIO code (both in nbio.c) and epoll's edge-triggered
> semantics.  This was the reason I decided to scrap the port when I first
> undertook it.
>
>    * Fortunately, epoll now also supports level-triggered semantics, which
> are essentially identical to the old /dev/poll.  With this, the port should
> be very straightforward - probably a matter of just replacing the various
> /dev/poll calls with their newer epoll equivalents.  Just a guess, but this
> is probably no more than a couple days work, if that.
>
> At this point, I don't have any need for an epoll-enabled SEDA myself, so
> I'm not planning to work on this.  I'd be happy to answer questions if you
> need some help getting started, though.
>
> Best,
>
> -Rob von Behren
>
>
>
> On Thu, 31 Jul 2003 17:25:26 -0700
>
> "jared allen" <[email protected]> wrote:
> > Has anyone implemented a version of NBIO that uses /dev/epoll  instead
> > of the standard poll and /dev/poll device drivers?
> > This is very important to the project I_m working and if anyone knows of
> > other projects that use NBIO that may have done this I_d love to know.
> > Also if anyone is interested in collaborating on a /dev/epoll
> > implementation would be great.
> >
> > Does anyone know what the JDK 1.4.1 and 1.4.2 nio use for polling?
> >
> > Thanks.
> > Jared Allen
>




-------------------------------------------------------
This SF.Net email sponsored by: Free pre-built ASP.NET sites including
Data Reports, E-commerce, Portals, and Forums are available now.
Download today and enter to win an XBOX or Visual Studio .NET.
http://aspnet.click-url.com/go/psa00100003ave/direct;at.aspnet_072303_01/01