package org.webpieces.nio.test.tcp;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import org.webpieces.util.logging.Logger;
import junit.framework.TestCase;
import org.webpieces.nio.api.channels.TCPChannel;
import org.webpieces.nio.api.deprecated.ChannelService;
import org.webpieces.nio.api.deprecated.ChannelServiceFactory;
import org.webpieces.nio.api.deprecated.ConnectionCallback;
import org.webpieces.nio.api.deprecated.Settings;
import org.webpieces.nio.api.handlers.DataListener;
import org.webpieces.nio.api.handlers.FutureOperation;
import org.webpieces.nio.api.handlers.OperationCallback;
import org.webpieces.nio.api.libs.BufferFactory;
import org.webpieces.nio.api.libs.BufferHelper;
import org.webpieces.nio.api.libs.FactoryCreator;
import org.webpieces.nio.api.testutil.CloneByteBuffer;
import org.webpieces.nio.api.testutil.HandlerForTests;
import org.webpieces.nio.test.EchoServer;
import org.webpieces.nio.test.PerfTimer;
import biz.xsoftware.mock.CalledMethod;
import biz.xsoftware.mock.MockObject;
import biz.xsoftware.mock.MockObjectFactory;
public abstract class ZPerformanceSuper extends TestCase {
private static final Logger log = LoggerFactory.getLogger(ZPerformanceSuper.class);
private BufferFactory bufFactory;
private InetSocketAddress svrAddr;
private ChannelService chanMgr;
//private InetAddress loopBack;
//private InetSocketAddress loopBackAnyPort;
private BufferHelper helper = ChannelServiceFactory.bufferHelper(null);
private MockObject mockHandler;
private MockObject mockConnect;
private EchoServer echoServer;
private MockObject mockConnectOp;
protected abstract ChannelService getClientChanMgr();
protected abstract ChannelService getServerChanMgr();
protected abstract Settings getServerFactoryHolder();
protected abstract Settings getClientFactoryHolder();
protected abstract String getChannelImplName();
public ZPerformanceSuper(String arg0) {
super(arg0);
if(bufFactory == null) {
Map<String, Object> map = new HashMap<String, Object>();
map.put(FactoryCreator.KEY_IS_DIRECT, false);
FactoryCreator creator = FactoryCreator.createFactory(null);
bufFactory = creator.createBufferFactory(map);
}
}
protected void setUp() throws Exception {
HandlerForTests.setupLogging();
LoggerFactory.getLogger("").setLevel(Level.INFO);
//here I keep using the same channel manager on purpose, just
//so we get testing between tests that the channel manager shutdown
//and started back up cleanly.....
if(chanMgr == null) {
chanMgr = getClientChanMgr();
}
if(echoServer == null) {
ChannelService svrChanMgr = getServerChanMgr();
echoServer = new EchoServer(svrChanMgr, getServerFactoryHolder());
}
chanMgr.start();
svrAddr = echoServer.start();
//this is to test EchoServer on a different machine...
// InetAddress tmp = InetAddress.getByName("192.168.1.102");
// svrAddr = new InetSocketAddress(tmp, 501);
log.trace("server port ="+svrAddr);
//loopBack = InetAddress.getByName("127.0.0.1");
//loopBackAnyPort = new InetSocketAddress(loopBack, 0);
mockHandler = MockObjectFactory.createMock(DataListener.class);
mockHandler.setDefaultBehavior("incomingData", new CloneByteBuffer());
mockConnect = MockObjectFactory.createMock(ConnectionCallback.class);
mockConnectOp = MockObjectFactory.createMock(OperationCallback.class);
}
protected void tearDown() throws Exception {
chanMgr.stop();
chanMgr = null;
echoServer.stop();
HandlerForTests.checkForWarnings();
Thread.sleep(1000);
LoggerFactory.getLogger("").setLevel(Level.FINEST);
}
protected abstract int getBasicConnectTimeLimit();
protected abstract int getSmallReadWriteTimeLimit();
protected abstract int getLargerReadWriteTimeLimit();
/**
* Testing difference between secureChanMgr with Basic, and just Basic
* and whatever other combinations are in PerfTestZ<Subclassname>. Here
* we are testing the performance of connect method. As you can see the
* establishing of a link is very expensive. 57 times difference!
*
* Basic ChannelMgr....
* time for initiating all connects = 180 ms
* time for initiating/finishing all connects = 180 ms
* time per connection = 4 ms
*
* Secure ChannelMgr....
* time for initiating all connects = 8,072 ms
* time for initiating/finishing all connects = 9,174 ms
* time per connection = 229 ms
*
*
* If you want to test difference between asynch connect and connect, you
* need to simulate a network delay in EchoServer class.
* I did this and simulated one second.
* Then changing the connect from synchronous to asynchronous results in going
* from 7.401 seconds to .531 seconds. ie. the thread calling connect is free
* to go do more work while in the process of connecting to a server or
* client for that matter.
*/
public void testBasicConnect() throws Exception {
int size = 40;
String[] methodNames = new String[size];
for(int i = 0; i < size; i++) {
methodNames[i] = "finished";
}
TCPChannel[] clients = new TCPChannel[size];
for(int i = 0; i < size; i++) {
clients[i] = chanMgr.createTCPChannel("Client["+i+"]", getClientFactoryHolder());
}
PerfTimer timer = new PerfTimer();
PerfTimer timer2 = new PerfTimer();
log.info("Starting test connecting to="+svrAddr);
timer.start();
timer2.start();
for(int i = 0; i < size; i++) {
FutureOperation future = clients[i].connect(svrAddr);
future.setListener((OperationCallback) mockConnectOp);
}
long result2 = timer2.stop();
mockConnectOp.expect(methodNames);
long result = timer.stop();
long timePerConnect = result/size;
log.info("time for initiating connects ="+result2);
log.info("time for initiating/finishing connects="+result);
log.info("connected per connection time ="+timePerConnect);
log.info("--time to beat ="+getBasicConnectTimeLimit());
assertTrue(timePerConnect < getBasicConnectTimeLimit());
}
/**
* Test used to test with netbeans profiler. Was seeing bizarre results where profiler
* claimed server selector thread was stuck on a monitor for 10 seconds but this is
* never shown in the snapshot, and is very bizarre. The most time spent in one
* of my methods if looked at the hotspot is from the main test thread, not the server
* selector thread which is bizarre as that thread showed no indication of being on a
* monitor.
*/
public void profilerTestConnectCloseBatches() throws Exception {
try {
log.info("test beginning");
int size = 10;
String[] methodNames = new String[size];
for(int i = 0; i < size; i++) {
methodNames[i] = "connected";
}
for(int j = 0; j < 10000; j++) {
TCPChannel[] clients = new TCPChannel[size];
for(int i = 0; i < size; i++) {
clients[i] = chanMgr.createTCPChannel("Client["+i+"]", getClientFactoryHolder());
}
for(int i = 0; i < size; i++) {
clients[i].oldConnect(svrAddr, (ConnectionCallback)mockConnect);
}
mockConnect.expect(methodNames);
for(TCPChannel channel : clients) {
channel.oldClose();
}
}
} catch(Exception e) {
log.error("the exception", e);
} finally {
log.erroring("test ending*********************");
}
// long timePerConnect = result/size;
// log.info("time for initiating connects ="+result2);
// log.info("time for initiating/finishing connects="+result);
// log.info("connected per connection time ="+timePerConnect);
// log.info("--time to beat ="+getBasicConnectTimeLimit());
// assertTrue(timePerConnect < getBasicConnectTimeLimit());
}
/**
* This is the difference in performance of writing/reading secure data vs.
* writing/reading non-secure data for a VERY SMALL payload. Realize though,
* in this test, the data is encrypted, decrypted, encrypted again, and
* decrypted again, so the server takes half this load, and the client the
* other half.
* Basic seems to be 75% of secure's time. This is a slowdown of 133%
* for echoing 'hello'.
*
* Basic....
* total write time =1732 ms
* total write/response time=1802 ms
* time per write/response =45 ms
* Secure....
* total write time =2374 ms
* total write/response time=2424 ms
* time per write/response =60 ms
* Basic with network delay of 1 seconds....
* total write time =1522 ms
* total write/response time=3585 ms
* time per write/response =89 ms
* @throws Exception
*/
public void testVerySmallReadWrite() throws Exception {
ByteBuffer b = ByteBuffer.allocate(4000);
log.info("getting all proper connections");
int size = 40;
String[] methodNames = new String[size];
for(int i = 0; i < size; i++) {
methodNames[i] = "finished";
}
TCPChannel[] clients = new TCPChannel[size];
for(int i = 0; i < size; i++) {
clients[i] = chanMgr.createTCPChannel("Client["+i+"]", getClientFactoryHolder());
FutureOperation future = clients[i].connect(svrAddr);
future.setListener((OperationCallback) mockConnectOp);
}
mockConnectOp.expect(methodNames);
log.info("done getting all connections");
for(TCPChannel client : clients) {
client.registerForReads((DataListener)mockHandler);
}
int numWrites = 200;
String payload = "hello";
helper.putString(b, payload);
helper.doneFillingBuffer(b);
int numBytes = b.remaining();
methodNames = new String[size];
for(int i = 0; i < size; i++) {
methodNames[i] = "incomingData";
}
String[] finNames = new String[size];
for(int i = 0;i < size;i++) {
finNames[i] = "finished";
}
PerfTimer timer = new PerfTimer();
PerfTimer timer2 = new PerfTimer();
timer.start();
timer2.start();
CalledMethod[] methods = null;
for(int i = 0; i < numWrites; i++) {
for(TCPChannel client : clients) {
FutureOperation write = client.write(b);
write.setListener((OperationCallback) mockConnectOp);
//client.oldWrite(b);
b.rewind();
}
mockConnectOp.expect(finNames);
methods = mockHandler.expect(methodNames);
}
long result2 = timer2.stop();
long result = timer.stop();
//pick a method and verify right data came back for performance test
//to make sure performance test is valid....
ByteBuffer actualBuf = (ByteBuffer)methods[5].getAllParams()[1];
String actual = helper.readString(actualBuf, actualBuf.remaining());
assertEquals(payload, actual);
log.info("payload="+actual);
long readWriteTime = result/size;
long byteTime = 100*result / (numWrites*numBytes);
log.info("total write time ="+result2);
log.info("total write/read time ="+result);
log.info("--time per 100 bytes ="+byteTime);
log.info("test result info:");
log.info("--time per write/read ="+readWriteTime);
log.info(" time to beat ="+getSmallReadWriteTimeLimit());
assertTrue(readWriteTime < getSmallReadWriteTimeLimit());
}
/**
* This is the difference in performance of writing/reading secure data vs.
* writing/reading non-secure data for a very small payload.
* Basic seems to be 75% of secure's time. This is a slowdown of 133%
* for echoing 'hello'.
*
* Basic....
* total write time = 1402 ms
* total write/response time= 1433 ms
* time per write/response = 35 ms
* Secure....
* total write time = 6119 ms
* total write/response time= 6159 ms
* time per write/response = 153 ms
*
* @throws Exception
*/
public void testLargeReadWrite() throws Exception {
ByteBuffer b = ByteBuffer.allocate(4000);
log.info("getting all proper connections");
int size = 40;
String[] methodNames = new String[size];
for(int i = 0; i < size; i++) {
methodNames[i] = "connected";
}
TCPChannel[] clients = new TCPChannel[size];
for(int i = 0; i < size; i++) {
clients[i] = chanMgr.createTCPChannel("Client["+i+"]", getClientFactoryHolder());
clients[i].oldConnect(svrAddr, (ConnectionCallback)mockConnect);
}
mockConnect.expect(methodNames);
log.info("done getting all connections");
for(TCPChannel client : clients) {
client.registerForReads((DataListener)mockHandler);
}
int numWrites = 100;
String payload = "hello";
for(int i = 0; i < 3000; i++) {
payload+="i";
}
helper.putString(b, payload);
helper.doneFillingBuffer(b);
int numBytes = b.remaining();
log.info("size="+b.remaining());
methodNames = new String[size*numWrites];
for(int i = 0; i < size*numWrites; i++) {
methodNames[i] = "incomingData";
}
PerfTimer timer = new PerfTimer();
PerfTimer timer2 = new PerfTimer();
timer.start();
timer2.start();
for(TCPChannel client : clients) {
for(int i = 0; i < numWrites; i++) {
FutureOperation future = client.write(b);
future.waitForOperation(5000);
b.rewind();
}
}
long result2 = timer2.stop();
CalledMethod[] methods = mockHandler.expect(methodNames);
long result = timer.stop();
ByteBuffer actualBuf = (ByteBuffer)methods[6].getAllParams()[1];
String actual = helper.readString(actualBuf, actualBuf.remaining());
assertEquals(payload, actual);
log.info("payload="+actual);
long readWriteTime = result/size;
long byteTime = 100*result / (numWrites*numBytes);
log.info("total write time ="+result2);
log.info("total write/read time ="+result);
log.info("--time per 100 bytes ="+byteTime);
log.info("test result info:");
log.info("--time per write/read ="+readWriteTime);
log.info("--time to beat ="+getLargerReadWriteTimeLimit());
assertTrue(readWriteTime < getLargerReadWriteTimeLimit());
}
public Object getBufFactory() {
return bufFactory;
}
}