jdk/src/demo/solaris/jni/Poller/README.txt
author lana
Wed, 23 Nov 2016 16:16:33 +0000
changeset 42234 29a0c1a888f2
parent 25859 3317bb8137f4
permissions -rw-r--r--
Added tag jdk-9+146 for changeset d139f0e91e7e
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     1
README.txt
90ce3da70b43 Initial load
duke
parents:
diff changeset
     2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     3
90ce3da70b43 Initial load
duke
parents:
diff changeset
     4
This Poller class demonstrates access to poll(2) functionality in Java.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     5
90ce3da70b43 Initial load
duke
parents:
diff changeset
     6
Requires Solaris production (native threads) JDK 1.2 or later, currently
90ce3da70b43 Initial load
duke
parents:
diff changeset
     7
the C code compiles only on Solaris (SPARC and Intel).
90ce3da70b43 Initial load
duke
parents:
diff changeset
     8
90ce3da70b43 Initial load
duke
parents:
diff changeset
     9
Poller.java is the class, Poller.c is the supporting JNI code.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    10
90ce3da70b43 Initial load
duke
parents:
diff changeset
    11
PollingServer.java is a sample application which uses the Poller class
90ce3da70b43 Initial load
duke
parents:
diff changeset
    12
to multiplex sockets.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    13
90ce3da70b43 Initial load
duke
parents:
diff changeset
    14
SimpleServer.java is the functional equivalent that does not multiplex
90ce3da70b43 Initial load
duke
parents:
diff changeset
    15
but uses a single thread to handle each client connection.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    16
90ce3da70b43 Initial load
duke
parents:
diff changeset
    17
Client.java is a sample application to drive against either server.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    18
90ce3da70b43 Initial load
duke
parents:
diff changeset
    19
To build the Poller class and client/server demo :
90ce3da70b43 Initial load
duke
parents:
diff changeset
    20
 javac PollingServer.java Client.java
90ce3da70b43 Initial load
duke
parents:
diff changeset
    21
 javah Poller
90ce3da70b43 Initial load
duke
parents:
diff changeset
    22
 cc -G -o libpoller.so -I ${JAVA_HOME}/include -I ${JAVA_HOME}/include/solaris\
90ce3da70b43 Initial load
duke
parents:
diff changeset
    23
  Poller.c
90ce3da70b43 Initial load
duke
parents:
diff changeset
    24
90ce3da70b43 Initial load
duke
parents:
diff changeset
    25
You will need to set the environment variable LD_LIBRARY_PATH to search
90ce3da70b43 Initial load
duke
parents:
diff changeset
    26
the directory containing libpoller.so.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    27
90ce3da70b43 Initial load
duke
parents:
diff changeset
    28
To use client/server, bump up your fd limit to handle the connections you
90ce3da70b43 Initial load
duke
parents:
diff changeset
    29
want (need root access to go beyond 1024).  For info on changing your file
90ce3da70b43 Initial load
duke
parents:
diff changeset
    30
descriptor limit, type "man limit".  If you are using Solaris 2.6
90ce3da70b43 Initial load
duke
parents:
diff changeset
    31
or later, a regression in loopback read() performance may hit you at low
90ce3da70b43 Initial load
duke
parents:
diff changeset
    32
numbers of connections, so run the client on another machine.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    33
90ce3da70b43 Initial load
duke
parents:
diff changeset
    34
BASICs of Poller class usage :
90ce3da70b43 Initial load
duke
parents:
diff changeset
    35
 run "javadoc Poller" or see Poller.java for more details.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    36
90ce3da70b43 Initial load
duke
parents:
diff changeset
    37
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
    38
    Poller Mux = new Poller(65535); // allow it to contain 64K IO objects
90ce3da70b43 Initial load
duke
parents:
diff changeset
    39
    
90ce3da70b43 Initial load
duke
parents:
diff changeset
    40
    int fd1 = Mux.add(socket1, Poller.POLLIN);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    41
    ...
90ce3da70b43 Initial load
duke
parents:
diff changeset
    42
    int fdN = Mux.add(socketN, Poller.POLLIN);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    43
90ce3da70b43 Initial load
duke
parents:
diff changeset
    44
    int[] fds = new int[100];
90ce3da70b43 Initial load
duke
parents:
diff changeset
    45
    short[] revents = new revents[100];
90ce3da70b43 Initial load
duke
parents:
diff changeset
    46
90ce3da70b43 Initial load
duke
parents:
diff changeset
    47
    int numEvents = Mux.waitMultiple(100, fds, revents, timeout);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    48
90ce3da70b43 Initial load
duke
parents:
diff changeset
    49
    for (int i = 0; i < numEvents; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    50
       /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
    51
        * Probably need more sophisticated mapping scheme than this!
90ce3da70b43 Initial load
duke
parents:
diff changeset
    52
	*/
90ce3da70b43 Initial load
duke
parents:
diff changeset
    53
        if (fds[i] == fd1) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    54
	    System.out.println("Got data on socket1");
90ce3da70b43 Initial load
duke
parents:
diff changeset
    55
	    socket1.getInputStream().read(byteArray);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    56
	    // Do something based upon state of fd1 connection
90ce3da70b43 Initial load
duke
parents:
diff changeset
    57
	}
90ce3da70b43 Initial load
duke
parents:
diff changeset
    58
	...
90ce3da70b43 Initial load
duke
parents:
diff changeset
    59
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    60
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
    61
90ce3da70b43 Initial load
duke
parents:
diff changeset
    62
Poller class implementation notes :
90ce3da70b43 Initial load
duke
parents:
diff changeset
    63
90ce3da70b43 Initial load
duke
parents:
diff changeset
    64
  Currently all add(),remove(),isMember(), and waitMultiple() methods
90ce3da70b43 Initial load
duke
parents:
diff changeset
    65
are synchronized for each Poller object.  If one thread is blocked in
90ce3da70b43 Initial load
duke
parents:
diff changeset
    66
pObj.waitMultiple(), another thread calling pObj.add(fd) will block
90ce3da70b43 Initial load
duke
parents:
diff changeset
    67
until waitMultiple() returns.  There is no provided mechanism to
90ce3da70b43 Initial load
duke
parents:
diff changeset
    68
interrupt waitMultiple(), as one might expect a ServerSocket to be in
90ce3da70b43 Initial load
duke
parents:
diff changeset
    69
the list waited on (see PollingServer.java).
90ce3da70b43 Initial load
duke
parents:
diff changeset
    70
90ce3da70b43 Initial load
duke
parents:
diff changeset
    71
  One might also need to interrupt waitMultiple() to remove()
90ce3da70b43 Initial load
duke
parents:
diff changeset
    72
fds/sockets, in which case one could create a Pipe or loopback localhost
90ce3da70b43 Initial load
duke
parents:
diff changeset
    73
connection (at the level of PollingServer) and use a write() to that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    74
connection to interrupt.  Or, better, one could queue up deletions
90ce3da70b43 Initial load
duke
parents:
diff changeset
    75
until the next return of waitMultiple().  Or one could implement an
90ce3da70b43 Initial load
duke
parents:
diff changeset
    76
interrupt mechanism in the JNI C code using a pipe(), and expose that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    77
at the Java level.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    78
90ce3da70b43 Initial load
duke
parents:
diff changeset
    79
  If frequent deletions/re-additions of socks/fds is to be done with
90ce3da70b43 Initial load
duke
parents:
diff changeset
    80
very large sets of monitored fds, the Solaris 7 kernel cache will
90ce3da70b43 Initial load
duke
parents:
diff changeset
    81
likely perform poorly without some tuning.  One could differentiate
90ce3da70b43 Initial load
duke
parents:
diff changeset
    82
between deleted (no longer cared for) fds/socks and those that are
90ce3da70b43 Initial load
duke
parents:
diff changeset
    83
merely being disabled while data is processed on their behalf.  In
90ce3da70b43 Initial load
duke
parents:
diff changeset
    84
that case, re-enabling a disabled fd/sock could put it in it's
90ce3da70b43 Initial load
duke
parents:
diff changeset
    85
original position in the poll array, thereby increasing the kernel
90ce3da70b43 Initial load
duke
parents:
diff changeset
    86
cache performance.  This would best be done in Poller.c.  Of course
90ce3da70b43 Initial load
duke
parents:
diff changeset
    87
this is not necessary for optimal /dev/poll performance.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    88
90ce3da70b43 Initial load
duke
parents:
diff changeset
    89
  Caution...the next paragraph gets a little technical for the
90ce3da70b43 Initial load
duke
parents:
diff changeset
    90
benefit of those who already understand poll()ing fairly well.  Others
90ce3da70b43 Initial load
duke
parents:
diff changeset
    91
may choose to skip over it to read notes on the demo server.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    92
90ce3da70b43 Initial load
duke
parents:
diff changeset
    93
  An optimal solution for frequent enabling/disabling of socks/fds
90ce3da70b43 Initial load
duke
parents:
diff changeset
    94
could involve a separately synchronized structure of "async"
90ce3da70b43 Initial load
duke
parents:
diff changeset
    95
operations.  Using a simple array (0..64k) containing the action
90ce3da70b43 Initial load
duke
parents:
diff changeset
    96
(ADD,ENABLE,DISABLE, NONE), the events, and the index into the poll
90ce3da70b43 Initial load
duke
parents:
diff changeset
    97
array, and having nativeWait() wake up in the poll() call periodically
90ce3da70b43 Initial load
duke
parents:
diff changeset
    98
to process these async operations, I was able to speed up performance
90ce3da70b43 Initial load
duke
parents:
diff changeset
    99
of the PollingServer by a factor of 2x at 8000 connections.  Of course
90ce3da70b43 Initial load
duke
parents:
diff changeset
   100
much of that gain was from the fact that I could (with the advent of
90ce3da70b43 Initial load
duke
parents:
diff changeset
   101
an asyncAdd() method) move the accept() loop into a separate thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
   102
from the main poll() loop, and avoid the overhead of calling poll()
90ce3da70b43 Initial load
duke
parents:
diff changeset
   103
with up to 7999 fds just for an accept.  In implementing the async
90ce3da70b43 Initial load
duke
parents:
diff changeset
   104
Disable/Enable, a further large optimization was to auto-disable fds
90ce3da70b43 Initial load
duke
parents:
diff changeset
   105
with events available (before return from nativeWait()), so I could
90ce3da70b43 Initial load
duke
parents:
diff changeset
   106
just call asyncEnable(fd) after processing (read()ing) the available
90ce3da70b43 Initial load
duke
parents:
diff changeset
   107
data.  This removed the need for inefficient gang-scheduling the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   108
attached PollingServer uses.  In order to separately synchronize the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   109
async structure, yet still be able to operate on it from within
90ce3da70b43 Initial load
duke
parents:
diff changeset
   110
nativeWait(), synchronization had to be done at the C level here.  Due
90ce3da70b43 Initial load
duke
parents:
diff changeset
   111
to the new complexities this introduced, as well as the fact that it
90ce3da70b43 Initial load
duke
parents:
diff changeset
   112
was tuned specifically for Solaris 7 poll() improvements (not
90ce3da70b43 Initial load
duke
parents:
diff changeset
   113
/dev/poll), this extra logic was left out of this demo.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   114
90ce3da70b43 Initial load
duke
parents:
diff changeset
   115
90ce3da70b43 Initial load
duke
parents:
diff changeset
   116
Client/Server Demo Notes :
90ce3da70b43 Initial load
duke
parents:
diff changeset
   117
90ce3da70b43 Initial load
duke
parents:
diff changeset
   118
  Do not run the sample client/server with high numbers of connections
90ce3da70b43 Initial load
duke
parents:
diff changeset
   119
unless you have a lot of free memory on your machine, as it can saturate
90ce3da70b43 Initial load
duke
parents:
diff changeset
   120
CPU and lock you out of CDE just by its very resource intensive nature
90ce3da70b43 Initial load
duke
parents:
diff changeset
   121
(much more so the SimpleServer than PollingServer).
90ce3da70b43 Initial load
duke
parents:
diff changeset
   122
90ce3da70b43 Initial load
duke
parents:
diff changeset
   123
  Different OS versions will behave very differently as far as poll()
90ce3da70b43 Initial load
duke
parents:
diff changeset
   124
performance (or /dev/poll existence) but, generally, real world applications
90ce3da70b43 Initial load
duke
parents:
diff changeset
   125
"hit the wall" much earlier when a separate thread is used to handle
90ce3da70b43 Initial load
duke
parents:
diff changeset
   126
each client connection.  Issues of thread synchronization and locking
90ce3da70b43 Initial load
duke
parents:
diff changeset
   127
granularity become performance killers.  There is some overhead associated
90ce3da70b43 Initial load
duke
parents:
diff changeset
   128
with multiplexing, such as keeping track of the state of each connection; as
90ce3da70b43 Initial load
duke
parents:
diff changeset
   129
the number of connections gets very large, however, this overhead is more
90ce3da70b43 Initial load
duke
parents:
diff changeset
   130
than made up for by the reduced synchronization overhead.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   131
90ce3da70b43 Initial load
duke
parents:
diff changeset
   132
  As an example, running the servers on a Solaris 7 PC (Pentium II-350 x 
90ce3da70b43 Initial load
duke
parents:
diff changeset
   133
2 CPUS) with 1 GB RAM, and the client on an Ultra-2, I got the following
90ce3da70b43 Initial load
duke
parents:
diff changeset
   134
times (shorter is better) :
90ce3da70b43 Initial load
duke
parents:
diff changeset
   135
90ce3da70b43 Initial load
duke
parents:
diff changeset
   136
  1000 connections :
90ce3da70b43 Initial load
duke
parents:
diff changeset
   137
90ce3da70b43 Initial load
duke
parents:
diff changeset
   138
PollingServer took 11 seconds
90ce3da70b43 Initial load
duke
parents:
diff changeset
   139
SimpleServer took 12 seconds
90ce3da70b43 Initial load
duke
parents:
diff changeset
   140
90ce3da70b43 Initial load
duke
parents:
diff changeset
   141
  4000 connections :
90ce3da70b43 Initial load
duke
parents:
diff changeset
   142
90ce3da70b43 Initial load
duke
parents:
diff changeset
   143
PollingServer took 20 seconds
90ce3da70b43 Initial load
duke
parents:
diff changeset
   144
SimpleServer took 37 seconds
90ce3da70b43 Initial load
duke
parents:
diff changeset
   145
90ce3da70b43 Initial load
duke
parents:
diff changeset
   146
  8000 connections :
90ce3da70b43 Initial load
duke
parents:
diff changeset
   147
90ce3da70b43 Initial load
duke
parents:
diff changeset
   148
PollingServer took 39 seconds
90ce3da70b43 Initial load
duke
parents:
diff changeset
   149
SimpleServer took 1:48 seconds
90ce3da70b43 Initial load
duke
parents:
diff changeset
   150
90ce3da70b43 Initial load
duke
parents:
diff changeset
   151
  This demo is not, however, meant to be considered some form of proof
90ce3da70b43 Initial load
duke
parents:
diff changeset
   152
that multiplexing with the Poller class will gain you performance; this
90ce3da70b43 Initial load
duke
parents:
diff changeset
   153
code is actually very heavily biased towards the non-polling server as
90ce3da70b43 Initial load
duke
parents:
diff changeset
   154
very little synchronization is done, and most of the overhead is in the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   155
kernel IO for both servers.  Use of multiplexing may be helpful in
90ce3da70b43 Initial load
duke
parents:
diff changeset
   156
many, but certainly not all, circumstances.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   157
90ce3da70b43 Initial load
duke
parents:
diff changeset
   158
  Benchmarking a major Java server application which can run
90ce3da70b43 Initial load
duke
parents:
diff changeset
   159
in a single-thread-per-client mode or using the  new Poller class showed
90ce3da70b43 Initial load
duke
parents:
diff changeset
   160
Poller provided a 253% improvement in throughput at a moderate load, as
90ce3da70b43 Initial load
duke
parents:
diff changeset
   161
well as a 300% improvement in peak capacity.  It also yielded a 21%
90ce3da70b43 Initial load
duke
parents:
diff changeset
   162
smaller memory footprint at the lower load level.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   163
90ce3da70b43 Initial load
duke
parents:
diff changeset
   164
  Finally, there is code in Poller.c to take advantage of /dev/poll
90ce3da70b43 Initial load
duke
parents:
diff changeset
   165
on OS versions that have that device; however, DEVPOLL must be defined
90ce3da70b43 Initial load
duke
parents:
diff changeset
   166
in compiling Poller.c (and it must be compiled on a machine with
90ce3da70b43 Initial load
duke
parents:
diff changeset
   167
/usr/include/sys/devpoll.h) to use it.  Code compiled with DEVPOLL
90ce3da70b43 Initial load
duke
parents:
diff changeset
   168
turned on will work on machines that don't have kernel support for
90ce3da70b43 Initial load
duke
parents:
diff changeset
   169
the device, as it will fall back to using poll() in those cases.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   170
Currently /dev/poll does not correctly return an error if you attempt
90ce3da70b43 Initial load
duke
parents:
diff changeset
   171
to remove() an object that was never added, but this should be fixed
90ce3da70b43 Initial load
duke
parents:
diff changeset
   172
in an upcoming /dev/poll patch.  The binary as shipped is not built with
90ce3da70b43 Initial load
duke
parents:
diff changeset
   173
/dev/poll support as our build machine does not have devpoll.h.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   174