Skip to content

Commit

Permalink
minor change to text value secondary parsing, hoping to speed it up a…
Browse files Browse the repository at this point in the history
… bit
  • Loading branch information
cowtowncoder committed Jan 28, 2014
1 parent 32e4e91 commit ac956fe
Show file tree
Hide file tree
Showing 3 changed files with 204 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/main/java/com/fasterxml/jackson/core/io/CharTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public final class CharTypes
*/
final static int[] sInputCodes;
static {
/* 96 would do for most cases (backslash is ascii 94)
/* 96 would do for most cases (backslash is ASCII 94)
* but if we want to do lookups by raw bytes it's better
* to have full table
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1504,6 +1504,8 @@ protected void _finishString2() throws IOException
{
char[] outBuf = _textBuffer.getCurrentSegment();
int outPtr = _textBuffer.getCurrentSegmentSize();
final int[] codes = _icLatin1;
final int maxCode = codes.length;

while (true) {
if (_inputPtr >= _inputEnd) {
Expand All @@ -1513,21 +1515,18 @@ protected void _finishString2() throws IOException
}
char c = _inputBuffer[_inputPtr++];
int i = (int) c;
if (i <= INT_BACKSLASH) {
if (i == INT_BACKSLASH) {
if (i < maxCode && codes[i] != 0) {
if (i == INT_QUOTE) {
break;
} else if (i == INT_BACKSLASH) {
/* Although chars outside of BMP are to be escaped as
* an UTF-16 surrogate pair, does that affect decoding?
* For now let's assume it does not.
*/
c = _decodeEscaped();
} else if (i <= INT_QUOTE) {
if (i == INT_QUOTE) {
break;
}
if (i < INT_SPACE) {
_throwUnquotedSpace(i, "string value");
}
}
} else if (i < INT_SPACE) {
_throwUnquotedSpace(i, "string value");
} // anything else?
}
// Need more room?
if (outPtr >= outBuf.length) {
Expand Down
194 changes: 194 additions & 0 deletions src/test/java/perf/ManualCharAccessTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
package perf;

public class ManualCharAccessTest
{
protected int hash;

protected final static byte[] SMALL_BYTE_CODES = new byte[256];

protected final static int[] SMALL_INT_CODES = new int[256];

protected final static int[] INT_CODES = new int[0x10000];
protected final static byte[] BYTE_CODES = new byte[0x10000];

static {
for (int i = 0; i < 32; ++i) {
if (!(i == '\r' || i == '\n' || i == '\t')) {
INT_CODES[i] = 1;
BYTE_CODES[i] = 1;
SMALL_BYTE_CODES[i] = 1;
SMALL_INT_CODES[i] = 1;
}
}
INT_CODES['\\'] = 2;
BYTE_CODES['\\'] = 2;
SMALL_BYTE_CODES['\\'] = 2;
SMALL_INT_CODES['\\'] = 2;
}

protected String generateString(int len)
{
int counter = 0;
StringBuilder sb = new StringBuilder(len + 20);
do {
sb.append("Some stuff: ").append(len).append("\n");
if ((++counter % 31) == 0) {
sb.append("\\");
}
} while (sb.length() < len);
return sb.toString();
}

private void test() throws Exception
{
final String INPUT_STR = generateString(23000);
final char[] INPUT_CHARS = INPUT_STR.toCharArray();
final char[] OUTPUT = new char[INPUT_CHARS.length];

// Let's try to guestimate suitable size, N megs of output
final int REPS = (int) ((double) (80 * 1000 * 1000) / (double) INPUT_CHARS.length);
System.out.printf("%d bytes to scan, will do %d repetitions\n",
INPUT_CHARS.length, REPS);

int i = 0;
int roundsDone = 0;
final int TYPES = 3;
final int WARMUP_ROUNDS = 5;

final long[] times = new long[TYPES];

while (true) {
int round = (i++ % TYPES);

String msg;
boolean lf = (round == 0);

long msecs;

switch (round) {
case 0:
msg = "Read classic";
msecs = readClassic(REPS, INPUT_CHARS, OUTPUT);
break;
case 1:
msg = "Read, byte[]";
msecs = readWithByte(REPS, INPUT_CHARS, OUTPUT);
break;
case 2:
msg = "Read, int[]";
msecs = readWithInt(REPS, INPUT_CHARS, OUTPUT);
break;
default:
throw new Error();
}
// skip first 5 rounds to let results stabilize
if (roundsDone >= WARMUP_ROUNDS) {
times[round] += msecs;
}

System.out.printf("Test '%s' [hash: 0x%s] -> %d msecs\n", msg, this.hash, msecs);
if (lf) {
++roundsDone;
if ((roundsDone % 7) == 0 && roundsDone > WARMUP_ROUNDS) {
double den = (double) (roundsDone - WARMUP_ROUNDS);
System.out.printf("Averages after %d rounds (classic, byte[], int[]): "
+"%.1f / %.1f / %.1f msecs\n",
(int) den
,times[0] / den, times[1] / den, times[2] / den
);

}
System.out.println();
}
if ((i % 17) == 0) {
System.out.println("[GC]");
Thread.sleep(100L);
System.gc();
Thread.sleep(100L);
}
}
}

private final long readClassic(int REPS, char[] input, char[] output) throws Exception
{
long start = System.currentTimeMillis();
final byte[] codes = BYTE_CODES;
final int MAX = 256;

while (--REPS >= 0) {
int outPtr = 0;
for (int i = 0, end = input.length; i < end; ++i) {
int ch = input[i];
if (ch < MAX && codes[ch] == NULL_BYTE) {
output[outPtr++] = (char) ch;
continue;
}
if (ch == '\\') {
output[outPtr++] = '_';
} else if (ch == '\n') {
output[outPtr++] = '_';
}
}
}
long time = System.currentTimeMillis() - start;
return time;
}

private final long readWithByte(int REPS, char[] input, char[] output) throws Exception
{
long start = System.currentTimeMillis();
final byte[] codes = BYTE_CODES;
while (--REPS >= 0) {
int outPtr = 0;
for (int i = 0, end = input.length; i < end; ++i) {
char ch = input[i];
if (codes[ch] == NULL_BYTE) {
output[outPtr++] = ch;
continue;
}
if (ch == '\\') {
output[outPtr++] = '_';
} else if (ch == '\n') {
output[outPtr++] = '_';
}
}
}
long time = System.currentTimeMillis() - start;
return time;
}

final static byte NULL_BYTE = (byte) 0;

private final long readWithInt(int REPS, char[] input, char[] output) throws Exception
{
long start = System.currentTimeMillis();
final int[] codes = INT_CODES;
while (--REPS >= 0) {
int outPtr = 0;

for (int i = 0, end = input.length; i < end; ++i) {
char ch = input[i];
if (codes[ch] != 0) {
output[outPtr++] = ch;
continue;
}
if (ch == '\\') {
output[outPtr++] = '_';
} else if (ch == '\n') {
output[outPtr++] = '_';
}
}
}
long time = System.currentTimeMillis() - start;
return time;
}

public static void main(String[] args) throws Exception
{
if (args.length != 0) {
System.err.println("Usage: java ...");
System.exit(1);
}
new ManualCharAccessTest().test();
}
}

0 comments on commit ac956fe

Please sign in to comment.