/**
* Copyright 2013, Landz and its contributors. All rights reserved.
*
* Licensed 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 z.net.stress;
import org.junit.Test;
import z.function.Pipeline;
import z.net.AsyncIOThreadPool;
import z.net.NetModule;
import z.net.PipelineContext;
import z.offheap.buffer.Buffer;
import z.offheap.buffer.Buffers;
import z.offheap.buffer.ByteBuffer;
import z.offheap.zmalloc.Allocator;
import z.util.Unsafes;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static z.offheap.zmalloc.Allocator.allocate;
import static z.offheap.zmalloc.Allocator.free;
import static z.util.Throwables.uncheck;
import static z.znr.socket.SocketAddressInet.LOOPBACK_ADDRESS;
import static z.znr.socket.Sockets.*;
/**
* in this test: only use one sequential tcp client
*/
public class NetModuleTestMT01 {
public static final long RUNS = 10_000_000L;
volatile long tid = 1;
@Test
public void basicTest() {
int port = 12345;
on(LOOPBACK_ADDRESS, port,
Pipeline
.create((PipelineContext ctx) -> {
ByteBuffer in = ctx.inBuffer;
ByteBuffer out = ctx.outBuffer;
long length = in.readableBytes();
in.readTo(out,length);
out.write((byte)length);//append a byte for length
tid = Unsafes.currentThreadId();
return ctx;
})
.end());
System.out.println("net server has started on "+ LOOPBACK_ADDRESS + " with port " + port);
uncheck(() -> Thread.sleep(3_000L));
int fd = socketTcp(); System.out.println("current client socket: "+fd);
connectTo(fd, LOOPBACK_ADDRESS, port);
String msg;
ThreadLocalRandom rnd = ThreadLocalRandom.current();
long count = RUNS;
while (count!=0) {
if ( (count%(RUNS/5))==0 ) {
System.gc();
uncheck(() -> Thread.sleep(1000L));
System.gc();
printStats("count="+count);
}
int length = rnd.nextInt(1,Byte.MAX_VALUE);
msg = randomString(length);
sendmsg(fd, msg);
recvmsg(fd, msg);
count--;
}
shutdown(fd);
}
private long lastReportedMem = 0;
private void printStats(String label) {
System.out.println("********************"+label+"********************");
System.out.println("+++++ heap usage stats @"+System.currentTimeMillis());
long usedMemory = Runtime.getRuntime().totalMemory()
- Runtime.getRuntime().freeMemory();
System.out.println("current used memory(in bytes):" + usedMemory);
System.out.println("delta to last reported(in bytes):" + (usedMemory-lastReportedMem));
lastReportedMem = usedMemory;
System.out.println("----- off-heap usage stats @"+System.currentTimeMillis()) ;
dumpGlobalStats(label,tid);
dumpTLPStats(label,tid);
System.out.println("********************"+label+"********************");
}
public static final void on(
String ipAddress, int port,
Pipeline<PipelineContext, PipelineContext> pipeline) {
AsyncIOThreadPool asyncIOPool =
new AsyncIOThreadPool(1, pipeline, AsyncIOThreadPool.NULL_CONSUMER);
NetModule net = new NetModule(asyncIOPool);
net.startServer(ipAddress,port);
}
public void connectTo(int fd, String ipAddress, int port) {
System.out.println("+++current thread now connects to server...");
int suc = connect(fd, ipAddress, port);
assertThat(suc, is(0));
System.out.println("+++socket["+fd+"] connected.");
}
public void sendmsg(int fd, String msg) {
// System.out.println("--->start to send msg["+msg+"]");
int msgLength = msg.length();
long cBuffer = allocate(msgLength);
for (int i = 0; i < msgLength; i++) {
Buffers.put(cBuffer + i, (byte) msg.charAt(i));
}
// System.out.println("--->current thread will block on writing...");
long csize = write(fd, cBuffer, msgLength);
assertThat((int)csize, is(msgLength));
free(cBuffer);
// System.out.println("--->msg has been sent.");
}
public void recvmsg(int fd, String msg) {
// System.out.println("<---start to receive msg:");
int msgLength = 1024;
try (ByteBuffer rb = Buffer.create(msgLength)) {
// System.out.println("<---current thread will block on writing...");
long n = read(fd, rb.address(), msgLength);
((Buffer) rb).skipWriteTo(n);
StringBuilder sb = new StringBuilder();
while (rb.readableBytes() != 1) {
sb.append((char) rb.read());
}
int a = rb.read();
assertThat(a, is(msg.length()));
assertThat((int) n, is(a+1));
assertThat(sb.toString(), is(msg));
// System.out.println("<---msg[" + sb + "] has been received.");
}
}
public void shutdown(int fd) {
System.out.println("===current thread will wait 3s to shutdown/close...");
uncheck(() -> Thread.sleep(3_000L));
int suc = shutdownWrite(fd);
assertThat(suc, is(0));
suc = close(fd);
assertThat(suc, is(0));
//
System.out.println("===client thread done.");
}
private static String randomString(int length) {
ThreadLocalRandom rnd = ThreadLocalRandom.current();
StringBuilder sb = new StringBuilder(32);
return rnd.ints(length)
.mapToObj(i -> Character.valueOf((char) (i & 0x7F)).toString())
.collect(Collectors.joining());
}
private static void dumpTLPStats(String label, long tid) {
System.out.println("\n==================="+label+"===================");
IntStream.range(0,34)
.forEach(sizeClass->
System.out.println(
"current Number Of TLP(current) AvaiablePages for sizeClass " +
sizeClass+ ": "+
Allocator.ManagedPoolStats.currentNumOfTLPAvaiablePages(tid,sizeClass))
);
}
private static void dumpGlobalStats(String label, long tid) {
System.out.println("\n====================="+label+"=====================");
System.out.println("current Number Of GP AvaiablePages:"+
Allocator.ManagedPoolStats.currentNumOfGPAvaiablePages());
System.out.println("current Number Of TLPs:"+
Allocator.ManagedPoolStats.currentNumOfTLPs());
System.out.println("current Number Of TLP(current) FreePages:"+
Allocator.ManagedPoolStats.currentNumOfTLPFreePages(tid));
}
}