/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.transport.udt.bench.xfer;
import static io.netty.transport.udt.util.UnitHelp.*;
import io.netty.transport.udt.bench.BenchXfer;
import io.netty.transport.udt.util.CaliperRunner;
import io.netty.transport.udt.util.TrafficControl;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import com.barchart.udt.SocketUDT;
import com.barchart.udt.StatusUDT;
import com.barchart.udt.TypeUDT;
import com.google.caliper.Param;
/**
* perform two way native UDT socket send/recv
*/
public class UdtNative extends BenchXfer {
@Param
private volatile int latency;
protected static List<String> latencyValues() {
return BenchXfer.latencyList();
}
@Param
private volatile int message;
protected static List<String> messageValues() {
return BenchXfer.messageList();
}
@Param
private volatile int duration;
protected static List<String> durationValues() {
return BenchXfer.durationList();
}
private volatile SocketUDT peer1;
private volatile SocketUDT peer2;
@Override
protected void setUp() throws Exception {
log.info("init");
TrafficControl.delay(latency);
final InetSocketAddress addr1 = localSocketAddress();
final InetSocketAddress addr2 = localSocketAddress();
peer1 = new SocketUDT(TypeUDT.DATAGRAM);
peer2 = new SocketUDT(TypeUDT.DATAGRAM);
peer1.setBlocking(false);
peer2.setBlocking(false);
peer1.setRendezvous(true);
peer2.setRendezvous(true);
peer1.bind(addr1);
peer2.bind(addr2);
socketAwait(peer1, StatusUDT.OPENED);
socketAwait(peer2, StatusUDT.OPENED);
peer1.connect(addr2);
peer2.connect(addr1);
socketAwait(peer1, StatusUDT.CONNECTED);
socketAwait(peer2, StatusUDT.CONNECTED);
peer1.setBlocking(true);
peer2.setBlocking(true);
super.setUp();
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
peer1.setBlocking(false);
peer2.setBlocking(false);
peer1.close();
peer2.close();
socketAwait(peer1, StatusUDT.CLOSED, StatusUDT.BROKEN);
socketAwait(peer2, StatusUDT.CLOSED, StatusUDT.BROKEN);
TrafficControl.delay(0);
log.info("done");
}
/** benchmark invocation */
public void timeMain(final int reps) throws Exception {
final int threadCount = 4;
final CountDownLatch completion = new CountDownLatch(threadCount);
final AtomicBoolean isOn = new AtomicBoolean(true);
final Runnable sendPeer1 = new Runnable() {
@Override
public void run() {
try {
while (isOn.get()) {
runCore();
}
} catch (final Exception e) {
log.error("", e);
} finally {
completion.countDown();
}
}
final ByteBuffer buffer = ByteBuffer.allocateDirect(message);
long sequence;
void runCore() throws Exception {
buffer.rewind();
buffer.putLong(0, sequence++);
final int count = peer1.send(buffer);
if (count != message) {
throw new Exception("count");
}
measure().rate().mark(count);
}
};
final Runnable sendPeer2 = new Runnable() {
@Override
public void run() {
try {
while (isOn.get()) {
runCore();
}
} catch (final Exception e) {
log.error("", e);
} finally {
completion.countDown();
}
}
final ByteBuffer buffer = ByteBuffer.allocateDirect(message);
long sequence;
void runCore() throws Exception {
buffer.rewind();
buffer.putLong(0, sequence++);
final int count = peer2.send(buffer);
if (count != message) {
throw new Exception("count");
}
}
};
final Runnable recvPeer1 = new Runnable() {
@Override
public void run() {
try {
while (isOn.get()) {
runCore();
}
} catch (final Exception e) {
log.error("", e);
} finally {
completion.countDown();
}
}
final ByteBuffer buffer = ByteBuffer.allocateDirect(message);
long sequence;
void runCore() throws Exception {
buffer.rewind();
final int count = peer1.receive(buffer);
if (count != message) {
throw new Exception("count");
}
if (this.sequence++ != buffer.getLong(0)) {
throw new Exception("sequence");
}
}
};
final Runnable recvPeer2 = new Runnable() {
@Override
public void run() {
try {
while (isOn.get()) {
runCore();
}
} catch (final Exception e) {
log.error("", e);
} finally {
completion.countDown();
}
}
final ByteBuffer buffer = ByteBuffer.allocateDirect(message);
long sequence;
void runCore() throws Exception {
buffer.rewind();
final int count = peer2.receive(buffer);
if (count != message) {
throw new Exception("count");
}
if (this.sequence++ != buffer.getLong(0)) {
throw new Exception("sequence");
}
}
};
final ExecutorService executor = Executors
.newFixedThreadPool(threadCount);
executor.submit(recvPeer1);
executor.submit(recvPeer2);
executor.submit(sendPeer1);
executor.submit(sendPeer2);
markWait(duration);
isOn.set(false);
completion.await();
executor.shutdownNow();
}
public static void main(final String[] args) throws Exception {
CaliperRunner.execute(UdtNative.class);
}
}