Hi,

Hope that I've created the valid test environment this time :-)

My last test results were (for me, at least) a little bit unclear so
I've recreated (very crude) the jk2's Java->C bridge.

Conclusion is that direct buffer access has only 5% higher throughput
and that's only cause there are two extra JNI calls, or perhaps the
ByteBuffer implementation of MsgAjp is faster (didn't done the Java side
profiling).
IMO the guys from Java team already implemented something like direct
buffer for the non-copy byte array case.

So, there is no need to switch to the new io unless we need that 5%.
On the other hand MsgAjp reimplements some of ByteBuffer functionality,
and IMO using it would be much cleaner solution, but conditional
compilation etc...

If someone can spare (waste ?) couple of hours I would be glad to get
the results from some nix platform.

MT.
 

Attachment: graph.gif
Description: GIF image

Dim WshShell, oExec, stdOut, cmdLine
Dim i, j, k
Dim fso, f, ts

Set WshShell = CreateObject("WScript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")

fso.CreateTextFile "testjava.csv"
Set f = fso.GetFile("testjava.csv")
Set ts = f.OpenAsTextStream(2, 0)
' Number of loops
j = 5000

ts.Write "Test;Handlers;Loops;Transfer Rate;Time" + vbCrLf

stdOut = ""
For k = 1 To 4
    cmdLine = "java Main -j " & j * k
    For i = 0 To 10
      Set oExec = WshShell.Exec(cmdLine)
      Do While Not oExec.StdOut.AtEndOfStream
        stdOut = stdOut & oExec.StdOut.ReadAll
      Loop
    Next
Next
ts.Write stdOut
ts.Close

fso.CreateTextFile "teststd.csv"
Set f = fso.GetFile("teststd.csv")
Set ts = f.OpenAsTextStream(2, 0)

ts.Write "Test;Handlers;Loops;Transfer Rate;Time" + vbCrLf

stdOut = ""
For k = 1 To 4
    cmdLine = "java Main -s " & j * k
    For i = 0 To 10
      Set oExec = WshShell.Exec(cmdLine)
      Do While Not oExec.StdOut.AtEndOfStream
        stdOut = stdOut & oExec.StdOut.ReadAll
      Loop
    Next
Next
ts.Write stdOut
ts.Close

fso.CreateTextFile "testnio.csv"
Set f = fso.GetFile("testnio.csv")
Set ts = f.OpenAsTextStream(2, 0)

ts.Write "Test;Handlers;Loops;Transfer Rate;Time" + vbCrLf

stdOut = ""
For k = 1 To 4
    cmdLine = "java Main -n " & j * k
    For i = 0 To 10
      Set oExec = WshShell.Exec(cmdLine)
      Do While Not oExec.StdOut.AtEndOfStream
        stdOut = stdOut & oExec.StdOut.ReadAll
      Loop
    Next
Next
ts.Write stdOut
ts.Close
#include <jni.h>
#include <stdlib.h>


jint standardSize = 0;
jint advancedSize = 0;
jbyte *advancedBuffer = NULL;
jbyte *standardBuffer = NULL;
jbyte *placeHolder;

JNIEXPORT jint JNICALL Java_AprImpl_jkInit
  (JNIEnv *env, jobject o, jlong xEnv, jlong componentP)
{
  placeHolder = (jbyte *)malloc(16384);
  /* completely dummy function */
    if (xEnv == 0 && componentP == 1)
      return 0;
    else
        return -1;
}


JNIEXPORT jint JNICALL Java_AprImpl_jkInitDirectBuffer
  (JNIEnv *env, jclass c, jlong xEnv, jlong commponentP, jobject directBuffer)
{
    
    if (directBuffer) {
        advancedBuffer = (jbyte *)((*env)->GetDirectBufferAddress(env, directBuffer));
    } 
    if (directBuffer) {
        advancedSize = (jint)((*env)->GetDirectBufferCapacity(env, directBuffer));
    }
    if (!advancedBuffer || !advancedSize)
        return -1;
    else
        return 0;    
}

JNIEXPORT jint JNICALL Java_AprImpl_jkInvoke
  (JNIEnv *env, jclass c, jlong dummy1, jlong dummy2, jlong dummy3, jint dummy4, 
   jbyteArray arrayBuffer, jint dummy5, jint length, jint dummy6)
{
    jbyte *buffer=NULL;
    jboolean iscopy;
    jint rv = 0;
    buffer = (jbyte *)((*env)->GetByteArrayElements(env, arrayBuffer, &iscopy));
    if (buffer) {
       standardBuffer = buffer;
//     memcpy(placeHolder, buffer, length);
       rv = length;
       (*env)->ReleaseByteArrayElements(env, arrayBuffer, buffer, 0);
    }

    return rv;     
}

JNIEXPORT jint JNICALL Java_AprImpl_jkInvokeDirect
  (JNIEnv *env, jclass c, jlong dummy1, jlong dummy2, jlong dummy3, 
   jint dummy4, jint dummy5, jint length, jint dummy6)
{
    jint rv = 0;
    if (advancedBuffer) {
//       memcpy(placeHolder, advancedBuffer, length);
       rv = length;
    }
    return rv;     
}
import java.nio.*;

class AprImpl {
    
    byte [] buffer;    
    long e;
    long c;
    long p;
    int jc;
    int jo;
    int jl;
    int jr;
    
    public native int jkInit( long xEnv, long componentP );

    public static native int jkInitDirectBuffer(long xEnv, long componentP , 
                                                ByteBuffer byteBuffer);
    public static native int jkInvoke(long xEnv, long componentP, long endpointP,
                                      int code, byte data[], int off, int len, int raw);    
    public static native int jkInvokeDirect(long xEnv, long componentP, long endpointP,
                                      int code, int off, int len, int raw);
    
    
    public int jkInvokeJava(long xEnv, long componentP, long endpointP,
                                      int code, byte data[], int off, int len, int raw)
    {
        System.arraycopy( data, 0, bufer, 0, len)
        buffer = data;
        e = xEnv;
        c = componentP;
        p = endpointP;
        jc = code;
        jo = off;
        jl = len;
        jr = raw;
        return buffer.length;
    }   
}

class ByteChunk {
    
    private byte [] buff;    
    
    public ByteChunk() {
        buff = new byte[4096];
        for (int i = 0; i < 4096; i++) {
            buff[i] = (byte)(48 + i % 10);     
        }
    }
    
    public byte[] getBuffer() {
        return buff;
    }
    
    public int getLength() {
        return buff.length;   
    }
}
import java.io.*;

public class JniHandler {

    protected AprImpl   apr = new AprImpl();    
    protected MsgAjp    msg = new MsgAjp();    
    protected MsgAjpNio nio = new MsgAjpNio();    
    
    
    public void initJkComponent() throws IOException {

        apr.jkInit( 0, 1 );
        apr.jkInitDirectBuffer( 0, 1 , nio.getBuffer());

    }
    
    protected int nativeDispatch(ByteChunk bc) throws IOException {
        msg.reset(); 
        msg.appendByteChunk(bc);
        msg.end();
        return apr.jkInvoke(0, 1, 2, 3, msg.getBuffer(), 4, msg.getLen(), 5);
    }    

    protected int nativeDispatchDirect(ByteChunk bc) throws IOException {
        nio.reset(); 
        nio.appendByteChunk(bc);
        nio.end();
        return apr.jkInvokeDirect(0, 1, 2, 3, 4, nio.getLen(), 5);
    }    

    protected int nativeDispatchJava(ByteChunk bc) throws IOException {
        return apr.jkInvokeJava(0, 1, 2, 3, msg.getBuffer(), 4, msg.getLen(), 5);
    }    
    
}
import java.io.*;


class Main {
    
    private JniHandler [] jnis;
    private long nTestBytes;
    
    static {
        System.loadLibrary("AprImpl");    
        
    }
    public void init(int nhandlers) {
        nTestBytes = 0;
        jnis = new JniHandler[nhandlers];
        try {
           for (int i = 0; i < nhandlers; i++) {
                jnis[i] = new JniHandler();
                jnis[i].initJkComponent();
            }
        }
        catch (IOException e) {
            System.err.println("IOException in init");
            return;
        }        
    }


    public void runStdTest(int ntimes) {
        for (int i = 0; i < ntimes; i++) {        
            try {
                for (int j = 0; j < jnis.length; j++) {
                    ByteChunk bc = new ByteChunk();
                    nTestBytes += jnis[j].nativeDispatch(bc);   
                }
             }
             catch (IOException e) {
                System.err.println("IOException in runStdTest");
                return;
             }        
        }
    }

    public void runNioTest(int ntimes) {
        for (int i = 0; i < ntimes; i++) {        
            try {
                for (int j = 0; j < jnis.length; j++) {
                    ByteChunk bc = new ByteChunk();
                    nTestBytes += jnis[j].nativeDispatchDirect(bc);   
                }
             }
             catch (IOException e) {
                System.err.println("IOException in runNioTest");
                return;
             }        
        }
    }
    
    public void runJavaTest(int ntimes) {        
        for (int i = 0; i < ntimes; i++) {        
            try {
                for (int j = 0; j < jnis.length; j++) {
                    ByteChunk bc = new ByteChunk();
                    nTestBytes += jnis[j].nativeDispatchJava(bc);   
                }
             }
             catch (IOException e) {
                System.err.println("IOException in runJavaTest");
                return;
             }        
        }
    }

    public long getBytes() {
        return nTestBytes;    
    }
    
    public void usage() {
        System.err.println("Usage: java Main <option> <loops> [handlers]");
        System.err.println("       options: -s  standard byte array");
        System.err.println("                -n  java.nio using ByteBuffer");                
        System.err.println("                -j  simple java consumer");                
    }    
    
    public static void main(String [] args) {
        int nhandlers = 1;
        int nloops = 0;
        int ntest = 0;
        
        long startTime;
        long initTime;
        long testTime;
        
        Main m = new Main();   

        if (args.length < 2) {
            m.usage();
            return;
        }
        if (args[0].equals("-s"))
            ntest = 1;
        else if (args[0].equals("-n"))
            ntest = 2;
        else if (args[0].equals("-j"))
            ntest = 3;
        else {
            m.usage();
            return;
        }
        
        nloops = Integer.parseInt(args[1]);
        if (args.length > 2)
            nhandlers = Integer.parseInt(args[2]);

        startTime = System.currentTimeMillis();        
        m.init(nhandlers);
        initTime = System.currentTimeMillis();        
        switch (ntest) {        
            case 1:
                m.runStdTest(nloops);
            break;  
            case 2:
                m.runNioTest(nloops);
            break;  
            case 3:
                m.runJavaTest(nloops);
            break;  
            
        }
        testTime = System.currentTimeMillis();        
        
        long t = 0;
        if ((testTime - initTime) > 0)
            t = (m.getBytes() * 1000 / (testTime - initTime))/(1024);
/*            
        System.out.println("Test finished");
        System.out.println("   initializing        :   " + (initTime - startTime));
        System.out.println("   testing time  (ms)  :   " + (testTime - initTime));
        System.out.println("   transfer rate (Kb/s):   " + t);
*/        
        /* semicolon separated values */
        System.out.println(ntest + ";" + nhandlers + ";" + 
                           nloops + ";" + t + ";" + (testTime - initTime));
        
    }    
        
}
import java.io.*;

public class MsgAjp {
    
    private byte buf[]=new byte[8300];

    private int pos;    
    private int len; 

    public void reset() {
        len = 4;
        pos = 4;
    }
        
    public void end() {
        len=pos;
        int dLen=len-4;

        buf[0] = (byte)0x41;
        buf[1] = (byte)0x42;
        buf[2]=  (byte)((dLen>>>8 ) & 0xFF );
        buf[3] = (byte)(dLen & 0xFF);
    }

    public byte[] getBuffer() {
        return buf;
    }    

    public void appendInt( int val ) {
        buf[pos++]   = (byte) ((val >>>  8) & 0xFF);
        buf[pos++] = (byte) (val & 0xFF);
    }

    public void appendByte( int val ) {
        buf[pos++] = (byte)val;
    }

    public void appendByteChunk(ByteChunk bc) throws IOException {
        if(bc==null) {
            appendInt( 0);
            appendByte(0);
            return;
        }

        byte[] bytes = bc.getBuffer();
        appendInt(bc.getLength());
        cpBytes(bytes, 0,  bc.getLength());
        appendByte(0);
    }

    private void cpBytes( byte b[], int off, int numBytes ) {
        if( pos + numBytes >= buf.length ) {
            return;
        }
        System.arraycopy( b, off, buf, pos, numBytes);
        pos += numBytes;
    }
  
    public int getLen() {
        return len;
    }
      
}
import java.io.*;
import java.nio.*;

public class MsgAjpNio {
    
    private ByteBuffer byteBuffer=ByteBuffer.allocateDirect(8300);

    public void reset() {
        byteBuffer.clear();
        byteBuffer.putInt(0);
    }
    
    public void end() {
        byteBuffer.put(0, (byte)0x41);
        byteBuffer.put(1, (byte)0x42);
        byteBuffer.putShort(2, (short)(byteBuffer.position() - 4));
    }

    public ByteBuffer getBuffer() {
        return byteBuffer;
    }

    public void appendInt( int val ) {
        byteBuffer.putShort((short)val);
    }

    public void appendByte( int val ) {
        byteBuffer.put((byte)val);
    }
    
    public void appendByteChunk(ByteChunk bc) throws IOException {
        if(bc==null) {
            appendInt( 0);
            appendByte(0);
            return;
        }

        appendInt( bc.getLength() );
        byteBuffer.put(bc.getBuffer());
        appendByte(0);
    }

    public int getLen() {
        return byteBuffer.position();
    }
    
}

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to