Cache least recently used output buffer.
- reduce memory allocations especially when Xml is serialized inside a tight inner loop, - performance slightly improved. BEFORE: 100 packages: [2/4] android.util.XmlPerfTest#timeWrite_Binary: PASSED (10.516s) timeWrite_Binary_mean: 674979 threadAllocCount_mean: 59 timeWrite_Binary_min: 671194 timeWrite_Binary_median: 674798 timeWrite_Binary_standardDeviation: 3658 threadAllocSize_mean: 530176 10 packages: [2/4] android.util.XmlPerfTest#timeWrite_Binary: PASSED (10.542s) timeWrite_Binary_mean: 71113 threadAllocCount_mean: 56 timeWrite_Binary_min: 70201 timeWrite_Binary_median: 71237 timeWrite_Binary_standardDeviation: 692 threadAllocSize_mean: 59136 1 package: [2/4] android.util.XmlPerfTest#timeWrite_Binary: PASSED (10.091s) timeWrite_Binary_mean: 15698 threadAllocCount_mean: 56 timeWrite_Binary_min: 15072 timeWrite_Binary_median: 15677 timeWrite_Binary_standardDeviation: 410 threadAllocSize_mean: 6439 AFTER: 100 packages: [1/1] android.util.XmlPerfTest#timeWrite_Binary: PASSED (10.221s) timeWrite_Binary_mean: 605862 threadAllocCount_mean: 53 timeWrite_Binary_min: 602353 timeWrite_Binary_median: 604424 timeWrite_Binary_standardDeviation: 4972 threadAllocSize_mean: 492748 10 packages: [1/1] android.util.XmlPerfTest#timeWrite_Binary: PASSED (10.575s) timeWrite_Binary_mean: 58710 threadAllocCount_mean: 50 timeWrite_Binary_min: 57551 timeWrite_Binary_median: 57798 timeWrite_Binary_standardDeviation: 2129 threadAllocSize_mean: 21696 1 package: [1/1] android.util.XmlPerfTest#timeWrite_Binary: PASSED (10.151s) timeWrite_Binary_mean: 11576 threadAllocCount_mean: 50 timeWrite_Binary_min: 11315 timeWrite_Binary_median: 11381 timeWrite_Binary_standardDeviation: 431 threadAllocSize_mean: 4336 Test: atest FastDataPerfTest XmlPerfTest Bug: 195994150 Fixes: 195994150 Merged-In: Ieedd27a676d718967c2fac30bc48a68ae636a180 Change-Id: Ieedd27a676d718967c2fac30bc48a68ae636a180
This commit is contained in:
committed by
Jeff Sharkey
parent
8a3803d401
commit
2be5b4c118
@@ -64,9 +64,13 @@ public class FastDataPerfTest {
|
||||
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
while (state.keepRunning()) {
|
||||
os.reset();
|
||||
final FastDataOutput out = new FastDataOutput(os, BUFFER_SIZE);
|
||||
doWrite(out);
|
||||
out.flush();
|
||||
final FastDataOutput out = FastDataOutput.obtain(os);
|
||||
try {
|
||||
doWrite(out);
|
||||
out.flush();
|
||||
} finally {
|
||||
out.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ public final class BinaryXmlSerializer implements TypedXmlSerializer {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
mOut = new FastDataOutput(os, BUFFER_SIZE);
|
||||
mOut = FastDataOutput.obtain(os);
|
||||
mOut.write(PROTOCOL_MAGIC_VERSION_0);
|
||||
|
||||
mTagCount = 0;
|
||||
@@ -138,7 +138,9 @@ public final class BinaryXmlSerializer implements TypedXmlSerializer {
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
mOut.flush();
|
||||
if (mOut != null) {
|
||||
mOut.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -157,6 +159,9 @@ public final class BinaryXmlSerializer implements TypedXmlSerializer {
|
||||
public void endDocument() throws IOException {
|
||||
mOut.writeByte(END_DOCUMENT | TYPE_NULL);
|
||||
flush();
|
||||
|
||||
mOut.release();
|
||||
mOut = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -30,6 +30,7 @@ import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* Optimized implementation of {@link DataOutput} which buffers data in memory
|
||||
@@ -41,23 +42,26 @@ import java.util.Objects;
|
||||
public class FastDataOutput implements DataOutput, Flushable, Closeable {
|
||||
private static final int MAX_UNSIGNED_SHORT = 65_535;
|
||||
|
||||
private static final int BUFFER_SIZE = 32_768;
|
||||
|
||||
private static AtomicReference<FastDataOutput> sOutCache = new AtomicReference<>();
|
||||
|
||||
private final VMRuntime mRuntime;
|
||||
private final OutputStream mOut;
|
||||
|
||||
private final byte[] mBuffer;
|
||||
private final long mBufferPtr;
|
||||
private final int mBufferCap;
|
||||
|
||||
private OutputStream mOut;
|
||||
private int mBufferPos;
|
||||
|
||||
/**
|
||||
* Values that have been "interned" by {@link #writeInternedUTF(String)}.
|
||||
*/
|
||||
private HashMap<String, Short> mStringRefs = new HashMap<>();
|
||||
private final HashMap<String, Short> mStringRefs = new HashMap<>();
|
||||
|
||||
public FastDataOutput(@NonNull OutputStream out, int bufferSize) {
|
||||
mRuntime = VMRuntime.getRuntime();
|
||||
mOut = Objects.requireNonNull(out);
|
||||
if (bufferSize < 8) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
@@ -65,6 +69,48 @@ public class FastDataOutput implements DataOutput, Flushable, Closeable {
|
||||
mBuffer = (byte[]) mRuntime.newNonMovableArray(byte.class, bufferSize);
|
||||
mBufferPtr = mRuntime.addressOf(mBuffer);
|
||||
mBufferCap = mBuffer.length;
|
||||
|
||||
setOutput(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new FastDataOutput object or retrieve one from cache.
|
||||
*/
|
||||
public static FastDataOutput obtain(@NonNull OutputStream out) {
|
||||
FastDataOutput instance = sOutCache.getAndSet(null);
|
||||
if (instance != null) {
|
||||
instance.setOutput(out);
|
||||
return instance;
|
||||
}
|
||||
return new FastDataOutput(out, BUFFER_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a FastDataOutput object back into the cache.
|
||||
* You must not touch the object after this call.
|
||||
*/
|
||||
public void release() {
|
||||
if (mBufferPos > 0) {
|
||||
throw new IllegalStateException("Lingering data, call flush() before releasing.");
|
||||
}
|
||||
|
||||
mOut = null;
|
||||
mBufferPos = 0;
|
||||
mStringRefs.clear();
|
||||
|
||||
if (mBufferCap == BUFFER_SIZE) {
|
||||
// Try to return to the cache.
|
||||
sOutCache.compareAndSet(null, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-initializes the object for the new output.
|
||||
*/
|
||||
private void setOutput(@NonNull OutputStream out) {
|
||||
mOut = Objects.requireNonNull(out);
|
||||
mBufferPos = 0;
|
||||
mStringRefs.clear();
|
||||
}
|
||||
|
||||
private void drain() throws IOException {
|
||||
@@ -83,6 +129,7 @@ public class FastDataOutput implements DataOutput, Flushable, Closeable {
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
mOut.close();
|
||||
release();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user