Skip to Content.
Sympa Menu

xom-interest - [XOM-interest] More Serializer performance patches

xom-interest AT lists.ibiblio.org

Subject: XOM API for Processing XML with Java

List archive

Chronological Thread  
  • From: Wolfgang Hoschek <whoschek AT lbl.gov>
  • To: xom-interest AT lists.ibiblio.org
  • Subject: [XOM-interest] More Serializer performance patches
  • Date: Tue, 19 Jul 2005 20:54:44 -0700

Here are some more Serializer performance patches against xom-1.1-CVS

1. improved UnicodeWriter.{writePCData, writeMarkup, writeAttributeValue) for strings that contain both portions that need - escaping and others that do not need escaping. Example: foo bar hello world foo bar
2. replace BufferedWriter used by Serializer with an unsynchronized custom version, enabling much better compiler inlining
3. revert Serializer.writeNamespaceDeclarations to previous impl (the recently changed CVS impl shows a 25% degradation)

Results: 1.5 - 2x faster for a wide range of documents
All tests pass after applying the patches.

[pabst /home/portnoy/u5/hoschek/tmp/tmp/firefish] bin/fire-java nux.xom.tests.BinaryXMLTest ser xom 0 2000 data/samples/data/randj.xml
patchesEnabled=true
now processing data/samples/data/randj.xml
compression factor = 1.0159606

****** SUMMARY ******
files = 2000
secs = 26.247
mean throughput MB/s = 16.981049
mean compression factor = 1.0159606
files/sec = 76.19919
checksum = 460010000
Dumping CPU usage by sampling running threads ... done.
[pabst /home/portnoy/u5/hoschek/tmp/tmp/firefish] less java.hprof.txt
[pabst /home/portnoy/u5/hoschek/tmp/tmp/firefish] bin/fire-java nux.xom.tests.BinaryXMLTest ser xom 0 6000 data/samples/data/ periodic.xml
patchesEnabled=true
now processing data/samples/data/periodic.xml
compression factor = 1.0296236

****** SUMMARY ******
files = 6000
secs = 27.234
mean throughput MB/s = 24.478483
mean compression factor = 1.0296236
files/sec = 220.31285
checksum = 678918000
Dumping CPU usage by sampling running threads ... done.
[pabst /home/portnoy/u5/hoschek/tmp/tmp/firefish]


Serializer.java:

// unsynchronized compact impl leads to much better inlining
static final class BufferedWriter extends Writer {
private final Writer out;
private int pos = 0;
private char buf[] = new char[CAPACITY];
private static final int CAPACITY = 8192;

public BufferedWriter(Writer out) {
super(out);
this.out = out;
}

public void write(int c) throws IOException {
if (pos >= CAPACITY) flushInternal();
buf[pos++] = (char) c;
}

public void write(String s) throws IOException {
write(s, 0, s.length());
}

public void write(String s, int off, int len) throws IOException {
while (len > 0) {
int n = Math.min(CAPACITY - pos, len);
s.getChars(off, off + n, buf, pos);
pos += n;
off += n;
len -= n;
if (pos >= CAPACITY) flushInternal();
}
}

public void flush() throws IOException {
flushInternal();
out.flush();
}

private void flushInternal() throws IOException {
if (pos != 0) {
out.write(buf, 0, pos);
pos = 0;
}
}

public void write(char[] chars, int off, int len) throws IOException {
throw new UnsupportedOperationException("not needed for XOM");
}

public void close() throws IOException {
throw new UnsupportedOperationException("not needed for XOM");
}




abstract class TextWriter {

protected final Serializer.BufferedWriter out; // WH // non- polymorphic use leads to much better inlining.

protected TextWriter(Writer out, String encoding) {
this.out = (Serializer.BufferedWriter) out;
this.encoding = encoding;
}



class UnicodeWriter extends TextWriter {

UnicodeWriter(Writer out, String encoding) {
super(out, encoding);
}

/**
* @see nu.xom.TextWriter#needsEscaping(char)
*/
boolean needsEscaping(char c) {
return false;
}

final void writeMarkup(String s) throws IOException { // WH
if (normalize) {
s = normalize(s);
}

int i = 0;
int length = s.length();

// example: foo bar hello world foo bar
while (i < length) {
int start = i;
int unicodeLength = 0;
char c;
// find run of chars that need no escaping
while (i < length && !mightNeedMarkupEscaping(c = s.charAt(i))) {
if (c < 0xd800 || c > 0xDBFF) unicodeLength++;
i++;
}
if (i > start) { // found chars that need no escaping; bulk write them
out.write(s, start, i-start);
if (unicodeLength > 0) {
column += unicodeLength;
lastCharacterWasSpace = false;
skipFollowingLinefeed = false;
justBroke=false;
}
}

// find and write individual chars that might need escaping
while (i < length && mightNeedMarkupEscaping(c = s.charAt (i))) {
writeMarkup(c);
i++;
}
}
}

final void writePCDATA(String s) throws IOException { // WH
if (normalize) {
s = normalize(s);
}

int i = 0;
int length = s.length();

while (i < length) {
int start = i;
int unicodeLength = 0;
char c;
// find run of chars that need no escaping
while (i < length && !mightNeedPCDATAEscaping(c = s.charAt(i))) {
if (c < 0xd800 || c > 0xDBFF) unicodeLength++;
i++;
}
if (i > start) { // found chars that need no escaping; bulk write them
out.write(s, start, i-start);
if (unicodeLength > 0) {
column += unicodeLength;
lastCharacterWasSpace = false;
skipFollowingLinefeed = false;
justBroke=false;
}
}

// find and write individual chars that might need escaping
while (i < length && mightNeedPCDATAEscaping(c = s.charAt (i))) {
writePCDATA(c);
i++;
}
}
}

// example: foo bar hello world foo bar
final void writeAttributeValue(String s) throws IOException { // WH
if (normalize) {
s = normalize(s);
}

int i = 0;
int length = s.length();

while (i < length) {
int start = i;
int unicodeLength = 0;
char c;
// find run of chars that need no escaping
while (i < length && !mightNeedAttributeEscaping(c = s.charAt(i))) {
if (c < 0xd800 || c > 0xDBFF) unicodeLength++;
i++;
}
if (i > start) { // found chars that need no escaping; bulk write them
out.write(s, start, i-start);
if (unicodeLength > 0) {
column += unicodeLength;
lastCharacterWasSpace = false;
skipFollowingLinefeed = false;
justBroke=false;
}
}

// find and write individual chars that might need escaping
while (i < length && mightNeedAttributeEscaping(c = s.charAt(i))) {
writeAttributeValue(c);
i++;
}
}
}

private static boolean mightNeedMarkupEscaping(char c) { // WH
return c <= ' ';
// switch (c) {
// case '\t': return true;
// case '\n': return true;
// case ' ': return true;
// default: return false;
// }
}

private static boolean mightNeedPCDATAEscaping(char c) { // WH
switch (c) {
case '&': return true;
case '<': return true;
case '>': return true;
case '\r':return true;

case '\t': return true;
case '\n': return true;
case ' ': return true;
default: return false;
}
}

private static boolean mightNeedAttributeEscaping(char c) { // WH
switch (c) {
case '\t': return true;
case '\n': return true;
case '"': return true;
case '\r': return true;
case '&': return true;
case '<': return true;
case '>': return true;
case ' ': return true;
default: return false;
}
}








Archive powered by MHonArc 2.6.24.

Top of Page