tom

More IO loop work.

package org.onlab.nio;
import org.onlab.util.Counter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -40,6 +41,10 @@ public abstract class MessageStream<M extends Message> {
private Exception ioError;
private long lastActiveTime;
private final Counter bytesIn = new Counter();
private final Counter messagesIn = new Counter();
private final Counter bytesOut = new Counter();
private final Counter messagesOut = new Counter();
/**
* Creates a message stream associated with the specified IO loop and
......@@ -93,6 +98,11 @@ public abstract class MessageStream<M extends Message> {
closed = true;
}
bytesIn.freeze();
bytesOut.freeze();
messagesIn.freeze();
messagesOut.freeze();
loop.removeStream(this);
if (key != null) {
try {
......@@ -176,6 +186,8 @@ public abstract class MessageStream<M extends Message> {
inbound.flip();
while ((message = read(inbound)) != null) {
messages.add(message);
messagesIn.add(1);
bytesIn.add(message.length());
}
inbound.compact();
......@@ -226,8 +238,9 @@ public abstract class MessageStream<M extends Message> {
while (outbound.remaining() < message.length()) {
doubleSize();
}
// Place the message into the buffer and bump the output trackers.
write(message, outbound);
messagesOut.add(1);
bytesOut.add(message.length());
}
// Forces a flush, unless one is planned already.
......@@ -273,6 +286,18 @@ public abstract class MessageStream<M extends Message> {
}
}
/**
* Indicates whether data has been written but not flushed yet.
*
* @return true if flush is required
*/
boolean isFlushRequired() {
synchronized (this) {
return outbound.position() > 0;
}
}
/**
* Attempts to flush data, internal stream state and channel availability
* permitting. Invoked by the driver I/O loop during handling of writable
......@@ -344,4 +369,40 @@ public abstract class MessageStream<M extends Message> {
return currentTimeMillis() - lastActiveTime > maxIdleMillis() && key != null;
}
/**
* Returns the inbound bytes counter.
*
* @return inbound bytes counter
*/
public Counter bytesIn() {
return bytesIn;
}
/**
* Returns the outbound bytes counter.
*
* @return outbound bytes counter
*/
public Counter bytesOut() {
return bytesOut;
}
/**
* Returns the inbound messages counter.
*
* @return inbound messages counter
*/
public Counter messagesIn() {
return messagesIn;
}
/**
* Returns the outbound messages counter.
*
* @return outbound messages counter
*/
public Counter messagesOut() {
return messagesOut;
}
}
......
/**
* Mechanism to transfer messages over network using IO loop and
* message stream, backed by NIO byte buffers.
*/
package org.onlab.nio;
\ No newline at end of file
package org.onlab.nio;
import org.onlab.util.Counter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -10,6 +11,7 @@ import java.net.SocketAddress;
import java.nio.channels.ByteChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
......@@ -26,9 +28,9 @@ import static org.onlab.util.Tools.namedThreads;
/**
* Auxiliary test fixture to measure speed of NIO-based channels.
*/
public class StandaloneSpeedClient {
public class IOLoopClient {
private static Logger log = LoggerFactory.getLogger(StandaloneSpeedClient.class);
private static Logger log = LoggerFactory.getLogger(IOLoopClient.class);
private final InetAddress ip;
private final int port;
......@@ -39,8 +41,8 @@ public class StandaloneSpeedClient {
private final ExecutorService ipool;
private final ExecutorService wpool;
// ThroughputTracker messages;
// ThroughputTracker bytes;
Counter messages;
Counter bytes;
/**
* Main entry point to launch the client.
......@@ -61,7 +63,7 @@ public class StandaloneSpeedClient {
log.info("Setting up client with {} workers sending {} {}-byte messages to {} server... ",
wc, mc, ml, ip);
StandaloneSpeedClient sc = new StandaloneSpeedClient(ip, wc, mc, ml, StandaloneSpeedServer.PORT);
IOLoopClient sc = new IOLoopClient(ip, wc, mc, ml, IOLoopServer.PORT);
sc.start();
delay(2000);
......@@ -82,7 +84,7 @@ public class StandaloneSpeedClient {
* @param port socket port
* @throws IOException if unable to create IO loops
*/
public StandaloneSpeedClient(InetAddress ip, int wc, int mc, int ml, int port) throws IOException {
public IOLoopClient(InetAddress ip, int wc, int mc, int ml, int port) throws IOException {
this.ip = ip;
this.port = port;
this.msgCount = mc;
......@@ -101,15 +103,15 @@ public class StandaloneSpeedClient {
* @throws IOException if unable to open connection
*/
public void start() throws IOException {
// messages = new ThroughputTracker();
// bytes = new ThroughputTracker();
messages = new Counter();
bytes = new Counter();
// First start up all the IO loops
for (CustomIOLoop l : iloops) {
ipool.execute(l);
}
// // Wait for all of them to get going
// Wait for all of them to get going
// for (CustomIOLoop l : iloops)
// l.waitForStart(TIMEOUT);
......@@ -151,20 +153,20 @@ public class StandaloneSpeedClient {
l.worker.task.get(secs, TimeUnit.SECONDS);
}
}
// messages.freeze();
// bytes.freeze();
messages.freeze();
bytes.freeze();
}
/**
* Reports on the accumulated throughput trackers.
*/
public void report() {
// DecimalFormat f = new DecimalFormat("#,##0");
// log.info("{} messages; {} bytes; {} mps; {} Mbs",
// f.format(messages.total()),
// f.format(bytes.total()),
// f.format(messages.throughput()),
// f.format(bytes.throughput() / (1024 * 128)));
DecimalFormat f = new DecimalFormat("#,##0");
log.info("{} messages; {} bytes; {} mps; {} Mbs",
f.format(messages.total()),
f.format(bytes.total()),
f.format(messages.throughput()),
f.format(bytes.throughput() / (1024 * 128)));
}
......@@ -187,16 +189,16 @@ public class StandaloneSpeedClient {
protected synchronized void removeStream(MessageStream<TestMessage> b) {
super.removeStream(b);
// messages.add(b.inMessages().total());
// bytes.add(b.inBytes().total());
// b.inMessages().reset();
// b.inBytes().reset();
// log.info("Disconnected client; inbound {} mps, {} Mbps; outbound {} mps, {} Mbps",
// StandaloneSpeedServer.format.format(b.inMessages().throughput()),
// StandaloneSpeedServer.format.format(b.inBytes().throughput() / (1024 * 128)),
// StandaloneSpeedServer.format.format(b.outMessages().throughput()),
// StandaloneSpeedServer.format.format(b.outBytes().throughput() / (1024 * 128)));
messages.add(b.messagesIn().total());
bytes.add(b.bytesIn().total());
b.messagesOut().reset();
b.bytesOut().reset();
//
log.info("Disconnected client; inbound {} mps, {} Mbps; outbound {} mps, {} Mbps",
IOLoopServer.FORMAT.format(b.messagesIn().throughput()),
IOLoopServer.FORMAT.format(b.bytesIn().throughput() / (1024 * 128)),
IOLoopServer.FORMAT.format(b.messagesOut().throughput()),
IOLoopServer.FORMAT.format(b.bytesOut().throughput() / (1024 * 128)));
}
@Override
......
......@@ -48,11 +48,11 @@ public class IOLoopIntegrationTest {
// Setup the test on a random port to avoid intermittent test failures
// due to the port being already bound.
int port = StandaloneSpeedServer.PORT + new Random().nextInt(100);
int port = IOLoopServer.PORT + new Random().nextInt(100);
InetAddress ip = InetAddress.getLoopbackAddress();
StandaloneSpeedServer sss = new StandaloneSpeedServer(ip, THREADS, size, port);
StandaloneSpeedClient ssc = new StandaloneSpeedClient(ip, THREADS, count, size, port);
IOLoopServer sss = new IOLoopServer(ip, THREADS, size, port);
IOLoopClient ssc = new IOLoopClient(ip, THREADS, count, size, port);
sss.start();
ssc.start();
......@@ -64,32 +64,6 @@ public class IOLoopIntegrationTest {
delay(1000);
sss.stop();
sss.report();
// Note that the client and server will have potentially significantly
// differing rates. This is due to the wide variance in how tightly
// the throughput tracking starts & stops relative to to the short
// test duration.
// System.out.println(f.format(ssc.messages.throughput()) + " mps");
// // Make sure client sent everything.
// assertEquals("incorrect client message count sent",
// (long) count * THREADS, ssc.messages.total());
// assertEquals("incorrect client bytes count sent",
// (long) size * count * THREADS, ssc.bytes.total());
//
// // Make sure server received everything.
// assertEquals("incorrect server message count received",
// (long) count * THREADS, sss.messages.total());
// assertEquals("incorrect server bytes count received",
// (long) size * count * THREADS, sss.bytes.total());
//
// // Make sure speeds were reasonable.
// if (mps > 0.0) {
// assertAboveThreshold("insufficient client speed", mps,
// ssc.messages.throughput());
// assertAboveThreshold("insufficient server speed", mps / 2,
// sss.messages.throughput());
// }
}
}
......
package org.onlab.nio;
import org.onlab.util.Counter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -23,9 +24,9 @@ import static org.onlab.util.Tools.namedThreads;
/**
* Auxiliary test fixture to measure speed of NIO-based channels.
*/
public class StandaloneSpeedServer {
public class IOLoopServer {
private static Logger log = LoggerFactory.getLogger(StandaloneSpeedServer.class);
private static Logger log = LoggerFactory.getLogger(IOLoopServer.class);
private static final int PRUNE_FREQUENCY = 1000;
......@@ -48,8 +49,8 @@ public class StandaloneSpeedServer {
private final int msgLength;
private int lastWorker = -1;
// ThroughputTracker messages;
// ThroughputTracker bytes;
Counter messages;
Counter bytes;
/**
* Main entry point to launch the server.
......@@ -64,7 +65,7 @@ public class StandaloneSpeedServer {
log.info("Setting up the server with {} workers, {} byte messages on {}... ",
wc, ml, ip);
StandaloneSpeedServer ss = new StandaloneSpeedServer(ip, wc, ml, PORT);
IOLoopServer ss = new IOLoopServer(ip, wc, ml, PORT);
ss.start();
// Start pruning clients.
......@@ -83,7 +84,7 @@ public class StandaloneSpeedServer {
* @param port listen port
* @throws IOException if unable to create IO loops
*/
public StandaloneSpeedServer(InetAddress ip, int wc, int ml, int port) throws IOException {
public IOLoopServer(InetAddress ip, int wc, int ml, int port) throws IOException {
this.workerCount = wc;
this.msgLength = ml;
this.ipool = Executors.newFixedThreadPool(workerCount, namedThreads("io-loop"));
......@@ -98,14 +99,14 @@ public class StandaloneSpeedServer {
* Start the server IO loops and kicks off throughput tracking.
*/
public void start() {
// messages = new ThroughputTracker();
// bytes = new ThroughputTracker();
messages = new Counter();
bytes = new Counter();
for (CustomIOLoop l : iloops) {
ipool.execute(l);
}
apool.execute(aloop);
//
// for (CustomIOLoop l : iloops)
// l.waitForStart(TIMEOUT);
// aloop.waitForStart(TIMEOUT);
......@@ -124,20 +125,20 @@ public class StandaloneSpeedServer {
// l.waitForFinish(TIMEOUT);
// aloop.waitForFinish(TIMEOUT);
//
// messages.freeze();
// bytes.freeze();
messages.freeze();
bytes.freeze();
}
/**
* Reports on the accumulated throughput trackers.
*/
public void report() {
// DecimalFormat f = new DecimalFormat("#,##0");
// log.info("{} messages; {} bytes; {} mps; {} Mbs",
// f.format(messages.total()),
// f.format(bytes.total()),
// f.format(messages.throughput()),
// f.format(bytes.throughput() / (1024 * 128)));
DecimalFormat f = new DecimalFormat("#,##0");
log.info("{} messages; {} bytes; {} mps; {} Mbs",
f.format(messages.total()),
f.format(bytes.total()),
f.format(messages.throughput()),
f.format(bytes.throughput() / (1024 * 128)));
}
/**
......@@ -170,15 +171,15 @@ public class StandaloneSpeedServer {
@Override
protected void removeStream(MessageStream<TestMessage> stream) {
super.removeStream(stream);
//
// messages.add(b.inMessages().total());
// bytes.add(b.inBytes().total());
//
// log.info("Disconnected client; inbound {} mps, {} Mbps; outbound {} mps, {} Mbps",
// format.format(b.inMessages().throughput()),
// format.format(b.inBytes().throughput() / (1024 * 128)),
// format.format(b.outMessages().throughput()),
// format.format(b.outBytes().throughput() / (1024 * 128)));
messages.add(stream.messagesIn().total());
bytes.add(stream.bytesIn().total());
log.info("Disconnected client; inbound {} mps, {} Mbps; outbound {} mps, {} Mbps",
FORMAT.format(stream.messagesIn().throughput()),
FORMAT.format(stream.bytesIn().throughput() / (1024 * 128)),
FORMAT.format(stream.messagesOut().throughput()),
FORMAT.format(stream.bytesOut().throughput() / (1024 * 128)));
}
@Override
......