[강운덕] [LUCYSUS-1744] datasender의 메모리 할당 및 copy를 줄임. cl로드 구조 변경에 따른 TestCase 를 수정

git-svn-id: http://svn.bds.nhncorp.com/pe/hippo-tomcat-profiler/trunk@1453 84d0f5b1-2673-498c-a247-62c4ff18d310
This commit is contained in:
Woonduk Kang
2013-04-12 08:53:10 +00:00
parent ead8cd4c0e
commit 2def838574
11 changed files with 269 additions and 49 deletions
+1 -1
View File
@@ -177,7 +177,7 @@ public class DefaultAgent implements Agent {
}
private void initializeTraceContext() {
this.traceContext = DefaultTraceContext.getTraceContext();
this.traceContext = new DefaultTraceContext();
this.traceContext.setAgentId(this.agentId);
this.traceContext.setApplicationId(this.applicationName);
@@ -14,6 +14,7 @@ import com.profiler.interceptor.bci.ByteCodeInstrumentor;
import com.profiler.interceptor.bci.JavaAssistByteCodeInstrumentor;
import com.profiler.modifier.ModifierRegistry;
@Deprecated
public class TomcatProfiler {
private static final Logger logger = LoggerFactory.getLogger(TomcatProfiler.class.getName());
@@ -23,17 +23,6 @@ public class DefaultTraceContext implements TraceContext {
private final Logger logger = LoggerFactory.getLogger(DefaultTraceContext.class.getName());
private static DefaultTraceContext CONTEXT = new DefaultTraceContext();
// initailze관련 생명주기가 뭔가 애매함. 추후 방안을 더 고려해보자.
public static TraceContext initialize() {
return CONTEXT = new DefaultTraceContext();
}
// 얻는 것도 뭔가 모양이 마음에 안듬.
public static DefaultTraceContext getTraceContext() {
return CONTEXT;
}
private final ThreadLocal<Trace> threadLocal = new NamedThreadLocal<Trace>("Trace");
@@ -22,7 +22,7 @@ public class HeaderTBaseSerializer {
* This is the byte array that data is actually serialized into
*/
// udp 패킷 사이즈에 최대 맞춤.
private final ByteArrayOutputStream baos_ = new ByteArrayOutputStream(1024 * 64);
private final UnsafeByteArrayOutputStream baos_ = new UnsafeByteArrayOutputStream(1024 * 64);
/**
* This transport wraps that byte array
@@ -39,7 +39,6 @@ public class HeaderTBaseSerializer {
*/
public HeaderTBaseSerializer() {
// this(new TBinaryProtocol.Factory());
this(new TCompactProtocol.Factory());
}
@@ -65,7 +64,13 @@ public class HeaderTBaseSerializer {
baos_.reset();
writeHeader(header);
base.write(protocol_);
return baos_.toByteArray();
// return baos_.toByteArray();
return baos_.getInterBuffer();
}
public int getInterBufferSize() {
return baos_.size();
}
private void writeHeader(Header header) throws TException {
@@ -0,0 +1,186 @@
package com.profiler.io;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
/**
*
*/
public class UnsafeByteArrayOutputStream extends OutputStream {
/**
* The buffer where data is stored.
*/
protected byte buf[];
/**
* The number of valid bytes in the buffer.
*/
protected int count;
/**
* Creates a new byte array output stream. The buffer capacity is
* initially 32 bytes, though its size increases if necessary.
*/
public UnsafeByteArrayOutputStream() {
this(32);
}
/**
* Creates a new byte array output stream, with a buffer capacity of
* the specified size, in bytes.
*
* @param size the initial size.
* @throws IllegalArgumentException if size is negative.
*/
public UnsafeByteArrayOutputStream(int size) {
if (size < 0) {
throw new IllegalArgumentException("Negative initial size: "
+ size);
}
buf = new byte[size];
}
/**
* Writes the specified byte to this byte array output stream.
*
* @param b the byte to be written.
*/
public void write(int b) {
int newcount = count + 1;
if (newcount > buf.length) {
buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
}
buf[count] = (byte) b;
count = newcount;
}
/**
* Writes <code>len</code> bytes from the specified byte array
* starting at offset <code>off</code> to this byte array output stream.
*
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
*/
public void write(byte b[], int off, int len) {
if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
int newcount = count + len;
if (newcount > buf.length) {
buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
}
System.arraycopy(b, off, buf, count, len);
count = newcount;
}
/**
* Writes the complete contents of this byte array output stream to
* the specified output stream argument, as if by calling the output
* stream's write method using <code>out.write(buf, 0, count)</code>.
*
* @param out the output stream to which to write the data.
* @throws java.io.IOException if an I/O error occurs.
*/
public void writeTo(OutputStream out) throws IOException {
out.write(buf, 0, count);
}
/**
* Resets the <code>count</code> field of this byte array output
* stream to zero, so that all currently accumulated output in the
* output stream is discarded. The output stream can be used again,
* reusing the already allocated buffer space.
*
* @see java.io.ByteArrayInputStream#count
*/
public void reset() {
count = 0;
}
/**
* Creates a newly allocated byte array. Its size is the current
* size of this output stream and the valid contents of the buffer
* have been copied into it.
*
* @return the current contents of this output stream, as a byte array.
* @see java.io.ByteArrayOutputStream#size()
*/
public byte toByteArray()[] {
return Arrays.copyOf(buf, count);
}
public byte[] getInterBuffer() {
return buf;
}
/**
* Returns the current size of the buffer.
*
* @return the value of the <code>count</code> field, which is the number
* of valid bytes in this output stream.
* @see java.io.ByteArrayOutputStream#count
*/
public int size() {
return count;
}
/**
* Converts the buffer's contents into a string decoding bytes using the
* platform's default character set. The length of the new <tt>String</tt>
* is a function of the character set, and hence may not be equal to the
* size of the buffer.
* <p/>
* <p> This method always replaces malformed-input and unmappable-character
* sequences with the default replacement string for the platform's
* default character set. The {@linkplain java.nio.charset.CharsetDecoder}
* class should be used when more control over the decoding process is
* required.
*
* @return String decoded from the buffer's contents.
* @since JDK1.1
*/
public String toString() {
return new String(buf, 0, count);
}
/**
* Converts the buffer's contents into a string by decoding the bytes using
* the specified {@link java.nio.charset.Charset charsetName}. The length of
* the new <tt>String</tt> is a function of the charset, and hence may not be
* equal to the length of the byte array.
* <p/>
* <p> This method always replaces malformed-input and unmappable-character
* sequences with this charset's default replacement string. The {@link
* java.nio.charset.CharsetDecoder} class should be used when more control
* over the decoding process is required.
*
* @param charsetName the name of a supported
* {@linkplain java.nio.charset.Charset </code>charset<code>}
* @return String decoded from the buffer's contents.
* @throws java.io.UnsupportedEncodingException
* If the named charset is not supported
* @since JDK1.1
*/
public String toString(String charsetName)
throws UnsupportedEncodingException {
return new String(buf, 0, count, charsetName);
}
/**
* Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
* this class can be called after the stream has been closed without
* generating an <tt>IOException</tt>.
* <p/>
*/
public void close() throws IOException {
}
}
@@ -36,6 +36,8 @@ public class UdpDataSender implements DataSender, Runnable {
private int maxDrainSize = 10;
// 주의 single thread용임
private List<Object> drain = new ArrayList<Object>(maxDrainSize);
// 주의 single thread용임
private DatagramPacket reusePacket = new DatagramPacket(new byte[1], 1);
private DatagramSocket udpSocket = null;
private Thread ioThread;
@@ -44,10 +46,13 @@ public class UdpDataSender implements DataSender, Runnable {
// 주의 single thread용임
private HeaderTBaseSerializer serializer = new HeaderTBaseSerializer();
private AtomicBoolean allowInput = new AtomicBoolean();
public UdpDataSender(String host, int port) {
Assert.notNull(host, "host must not be null");
if (host == null ) {
throw new NullPointerException("host must not be null");
}
// Socket 생성에 에러가 발생하면 Agent start가 안되게 변경.
this.udpSocket = createSocket(host, port);
@@ -69,7 +74,8 @@ public class UdpDataSender implements DataSender, Runnable {
private DatagramSocket createSocket(String host, int port) {
try {
DatagramSocket datagramSocket = new DatagramSocket();
DatagramSocket datagramSocket = new DatagramSocket();
datagramSocket.setSoTimeout(1000 * 5);
InetSocketAddress serverAddress = new InetSocketAddress(host, port);
@@ -169,6 +175,8 @@ public class UdpDataSender implements DataSender, Runnable {
}
}
private void sendPacket(Object dto) {
TBase<?, ?> tBase;
if (dto instanceof TBase) {
@@ -179,15 +187,16 @@ public class UdpDataSender implements DataSender, Runnable {
logger.warn("sendPacket fail. invalid type:" + dto.getClass());
return;
}
// TODO single thread이므로 데이터 array를 nocopy해서 보낼수 있음.
byte[] sendData = serialize(tBase);
if (sendData == null) {
logger.warn("sendData is null");
// single thread이므로 데이터 array를 nocopy해서 보.
byte[] interBufferData = serialize(tBase);
int interBufferSize = serializer.getInterBufferSize();
if (interBufferData == null) {
logger.warn("interBufferData is null");
return;
}
DatagramPacket packet = new DatagramPacket(sendData, sendData.length);
reusePacket.setData(interBufferData, 0, interBufferSize);
try {
udpSocket.send(packet);
udpSocket.send(reusePacket);
if (logger.isInfoEnabled()) {
logger.info("Data sent. " + dto);
}
@@ -229,6 +238,10 @@ public class UdpDataSender implements DataSender, Runnable {
}
}
private int beforeSerializeLength() {
return serializer.getInterBufferSize();
}
private Header headerLookup(TBase<?, ?> dto) throws TException {
// header 객체 생성을 안하고 정적 lookup이 되도록 변경.
return locator.headerLookup(dto);